/* =============================================================
   Portfolio — CRT terminal
   Layers, bottom to top:
     .terminal  → the Claude-Code-ish session
     .hal       → the red eye (fades in over the terminal)
     .site      → the portfolio (revealed after the break)
     .glass / .scanlines / .flicker / .vignette → screen FX
   State is driven by classes on #monitor:
     .is-hal  .is-breaking  .is-broken
   ============================================================= */

:root {
  --phosphor:        #4dff9f;
  --phosphor-dim:    #2f9e63;
  --phosphor-soft:   #c6f7dc;
  --phosphor-glow:   rgba(77, 255, 159, .45);
  --amber:           #ffcf6b;
  --hal-red:         #ff2b17;
  --screen-bg:       #061109;

  /* Apple II era case plastic — warm beige ABS, yellowed with age */
  --plastic:         #d9d2bd;
  --plastic-hi:      #e6e0cd;
  --plastic-lo:      #bdb5a0;
  --plastic-shadow:  #6d6350;
  --silkscreen:      #6b6152;
  /* the well around the tube is the same case plastic, sitting in shadow */
  --bezel-hi:        #b0a794;
  --bezel:           #a29985;
  --bezel-lo:        #8f8674;
  /* narrow near-black mask between the plastic and the glass */
  --tube-mask:       #2f2d28;
  /* parting line where the bezel moulding meets the outer shell */
  /* front face of the real machine, measured off the photo: ~1.35 wide to
     tall, i.e. the 4:3 of the era. Kept as a plain number so the same value
     drives both aspect-ratio and the width calc below. */
  --case-ratio:      1.3333;
  /* width of the case plastic around the well. the right side is the .chin
     strip rather than padding, so the two are kept in step by this value. */
  --case-pad:        46px;
  /* room padding top+bottom, plus the gap and the "press esc" line below */
  --room-chrome:     calc(2 * clamp(8px, 2.4vmin, 34px) + 44px);
  --case-groove:     #40392a;
  --groove-w:        clamp(2px, .3vmin, 4px);

  /* The room: papered wall above a chair rail, wood desk below. Warm and
     dim — a lamp somewhere off the top of frame, the monitor doing the rest. */
  --wall-lit:       #7d7159;
  --wall:           #574e3d;
  --wall-dark:      #2b271e;
  --rail:           #4a3c28;
  --desk-lit:       #6b4f30;
  --desk:           #4e3a22;
  --desk-dark:      #241a0f;
  /* the lamp out of frame above */
  --lamp:           255, 214, 150;
  /* colour the monitor throws into the room; flips red when HAL takes over */
  --room-light:     77, 255, 159;

  --mono: "JetBrains Mono", ui-monospace, "SF Mono", SFMono-Regular,
          "Cascadia Mono", Consolas, "Liberation Mono", monospace;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--wall);
  font-family: var(--mono);
  color: var(--phosphor);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

/* ---------- room / layout ---------- */

.room {
  position: relative;
  isolation: isolate;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: clamp(8px, 2.4vmin, 34px);
  gap: 14px;
}

/* Back wall. A pool of light sits behind the monitor and falls off toward
   the corners; the screen adds its own coloured spill on top.
   Both room planes are absolutely positioned so they stay out of the
   flex flow and never become flex items. */
.room::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    /* the screen's own colour landing on the paper */
    radial-gradient(ellipse 70% 52% at 50% 44%,
                    rgba(var(--room-light), .07), transparent 70%),
    /* warm pool from a lamp somewhere above the frame */
    radial-gradient(ellipse 90% 55% at 50% -8%,
                    rgba(var(--lamp), .20), transparent 70%),
    /* chair rail — the wall is papered above it, and it catches a highlight
       on its top edge and drops a shadow below */
    linear-gradient(180deg,
      transparent 0 61.5%,
      rgba(255,255,255,.10) 61.5% 62.2%,
      var(--rail) 62.2% 64.4%,
      rgba(0,0,0,.3) 64.4% 65.1%,
      transparent 65.1%),
    /* woodchip paper: two off-axis stipples so the texture never lines up
       into visible stripes */
    repeating-linear-gradient(96deg,
      rgba(255,255,255,.035) 0 1px, transparent 1px 4px),
    repeating-linear-gradient(-84deg,
      rgba(0,0,0,.05) 0 1px, transparent 1px 5px),
    /* the wall itself, falling off into the corners */
    radial-gradient(ellipse 115% 85% at 50% 34%,
                    var(--wall-lit) 0%, var(--wall) 50%, var(--wall-dark) 100%);
}

/* Desk. The inset top highlight is the far edge catching the screen light —
   it reads as the horizon where the desk meets the wall. */
.room::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 30%;
  z-index: 0;
  background:
    /* screen light pooling on the veneer right in front of the machine */
    radial-gradient(ellipse 55% 130% at 50% 0%,
                    rgba(var(--room-light), .11), transparent 72%),
    radial-gradient(ellipse 80% 120% at 50% -10%,
                    rgba(var(--lamp), .12), transparent 70%),
    /* wood grain: irregular stop widths so it reads as timber rather than
       a regular stripe pattern */
    repeating-linear-gradient(90deg,
      rgba(0,0,0,.10)      0 2px,   transparent 2px 9px,
      rgba(255,255,255,.05) 9px 10px, transparent 10px 23px,
      rgba(0,0,0,.07)     23px 24px, transparent 24px 41px),
    linear-gradient(180deg, var(--desk-lit) 0%, var(--desk) 28%, var(--desk-dark) 100%);
  /* far edge of the desk catching the light */
  box-shadow: 0 1px 0 rgba(255, 255, 255, .12) inset;
}

/* HAL's red replaces the phosphor glow everywhere the monitor lights the room */
.room:has(.is-breaking, .is-broken) {
  --room-light: 255, 43, 23;
}

/* ---------- monitor shell ---------- */

.monitor {
  position: relative;
  z-index: 1;
  /* The case keeps the machine's proportions at every size: width is capped
     by the room, by 1180px, and by whatever height is left over. Height then
     falls out of the aspect ratio, so the ratio is never the thing that gives. */
  aspect-ratio: var(--case-ratio);
  width: min(100%, 1180px, calc((100dvh - var(--room-chrome)) * var(--case-ratio)));
  height: auto;
  flex: 0 0 auto;
  display: flex;
  /* the tube well, then the strip of case that carries the lamp and badge */
  flex-direction: row;
  /* boxy moulded case — barely-there radius, wide front face */
  border-radius: 10px;
  /* no right padding — the .chin strip supplies that edge */
  padding: var(--case-pad) 0 var(--case-pad) var(--case-pad);
  background:
    /* fine vertical grain of textured ABS */
    repeating-linear-gradient(90deg,
      rgba(255,255,255,.022) 0 1px, transparent 1px 3px),
    linear-gradient(180deg,
      var(--plastic-hi) 0%, var(--plastic) 30%, var(--plastic) 62%, var(--plastic-lo) 100%);
  box-shadow:
    /* moulded top edge catching the room light, dark lip underneath */
    0 1px 0 rgba(255,255,255,.5) inset,
    0 -2px 0 rgba(109,99,80,.55) inset,
    0 -40px 70px -30px rgba(109,99,80,.5) inset,
    /* the case's shadow on the veneer behind and under it */
    0 40px 80px -20px rgba(26,16,6,.8),
    0 0 140px -30px rgba(var(--room-light), .14);
}

/* The CRT sits in a deep well cut into the front of the case. The bezel is
   the beige surround holding the tube — a separate moulding, so a shadowed
   parting line runs around it where it meets the outer shell. */
.bezel {
  flex: 1;
  min-width: 0;
  min-height: 0;
  padding: 42px;
  border-radius: 14px;
  background:
    linear-gradient(180deg,
      var(--bezel) 0%, var(--bezel-hi) 38%, var(--bezel-hi) 62%, var(--bezel-lo) 100%);
  box-shadow:
    /* the overhang above the well drops a shadow onto the plastic inside it */
    0 10px 22px -6px rgba(58,50,36,.55) inset,
    /* edge of the bezel piece itself */
    0 0 0 1px rgba(70,62,48,.5),
    /* the case overhang shades the top of the channel more than the bottom */
    0 -2px 3px var(--groove-w) rgba(58,50,36,.5),
    /* the parting line: the bezel is a separate moulding snapped into the
       shell, leaving a shadowed channel all the way around it */
    0 0 0 var(--groove-w) var(--case-groove),
    /* far wall of the channel, catching light from up-front */
    0 0 0 calc(var(--groove-w) + 1px) rgba(255,255,255,.42);
}

/* ---------- the screen ---------- */

.screen {
  position: relative;
  height: 100%;
  min-height: 0;
  aspect-ratio: auto;
  /* the glass corners are generously rounded on a tube this old */
  border-radius: 20px;
  overflow: hidden;
  background:
    radial-gradient(ellipse 100% 80% at 50% 40%, #0b1c12 0%, var(--screen-bg) 70%, #030805 100%);
  box-shadow:
    0 0 60px rgba(var(--room-light), .10) inset,
    /* the dark mask ringing the tube, then the light it throws on the plastic */
    0 0 0 1px rgba(0,0,0,.9),
    0 0 0 clamp(4px, .7vmin, 9px) var(--tube-mask),
    0 0 0 calc(clamp(4px, .7vmin, 9px) + 1px) rgba(90,80,62,.6),
    0 0 30px -2px rgba(var(--room-light), .28);
  isolation: isolate;
}

/* ---------- chin ---------- */

.chin {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 140px;
  align-items: flex-end;
  padding-right: 30px;
}

/* Six-stripe badge, the way the machines of this era wore their colours */
.rainbow {
  width: 20px;
  height: 20px;
  border-radius: 4px;
  background: linear-gradient(180deg,
    #61bb46 0 16.66%,
    #fdb827 16.66% 33.33%,
    #f5821f 33.33% 50%,
    #e03a3e 50% 66.66%,
    #963d97 66.66% 83.33%,
    #009ddc 83.33% 100%);
  opacity: .85;
  box-shadow: 0 1px 1px rgba(109,99,80,.4);
}

/* silkscreened, so it sits slightly debossed into the plastic —
   set vertically to run up the narrow strip of case */
.brand {
  writing-mode: vertical-rl;
  font-size: 10px;
  letter-spacing: .28em;
  color: var(--silkscreen);
  text-transform: uppercase;
  text-shadow: 0 1px 0 rgba(255,255,255,.35);
}

/* the lamp and the badge each sit in a small pocket moulded into the case */
.led-container,
.rainbow-container {
  padding: 16px;
  border-radius: 4px;
  background-color: #0000002b;
  box-shadow:
    /* light from above: the top wall of the pocket falls into shadow, the
       bottom wall catches it */
    0 4px 6px -2px rgba(40,34,24,.6) inset,
    0 -2px 4px -1px rgba(255,255,255,.16) inset,
    /* lip of the pocket where it meets the case face */
    0 -1px 0 rgba(109,99,80,.5),
    0 1px 0 rgba(255,255,255,.4);
}

/* power lamp, set into the plastic */
.led {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--phosphor);
  box-shadow:
    0 0 0 1px rgba(109,99,80,.55),
    0 0 10px 2px var(--phosphor-glow);
  transition: background .4s, box-shadow .4s;
}

.is-broken .led,
.is-breaking .led {
  background: var(--hal-red);
  box-shadow:
    0 0 0 1px rgba(109,99,80,.55),
    0 0 12px 3px rgba(255,43,23,.65);
  animation: led-blink 1.1s steps(1) infinite;
}

/* =============================================================
   TERMINAL
   ============================================================= */

.terminal {
  position: absolute;
  inset: 0;
  padding: clamp(14px, 2.6vmin, 30px);
  overflow: hidden;
  transition: opacity .6s ease, filter .6s ease;
}

.term-scroll {
  height: 100%;
  overflow-y: auto;
  scrollbar-width: none;
  font-size: clamp(12px, 1.5vmin, 15px);
  line-height: 1.65;
  text-shadow: 0 0 6px var(--phosphor-glow);
}
.term-scroll::-webkit-scrollbar { display: none; }

.term-out { white-space: pre-wrap; word-break: break-word; }

.term-out .dim    { color: var(--phosphor-dim); }
.term-out .accent { color: var(--amber); text-shadow: 0 0 8px rgba(255,207,107,.4); }
.term-out .user   { color: var(--phosphor-soft); }
.term-out .err    { color: var(--hal-red); text-shadow: 0 0 8px rgba(255,43,23,.5); }

/* the login line, before the agent prompt appears */
.login-row {
  margin: 4px 0 2px;
  color: var(--phosphor-dim);
}
.login-label { color: var(--phosphor-dim); }
.login-value { color: var(--phosphor-soft); }
/* the login cursor blinks whether or not the field has focus */
.login-row .cursor { translate: 0 .2em; }

.term-out .who { color: var(--phosphor-soft); }

/* the welcome banner */
.banner {
  border: 1px solid var(--phosphor-dim);
  border-radius: 8px;
  padding: 10px 14px;
  margin: 6px 0 16px;
  display: inline-block;
  min-width: min(100%, 460px);
}

/* Claude-Code-ish input box */
.prompt-box {
  position: relative;
  margin-top: 18px;
  border: 1px solid var(--phosphor-dim);
  border-radius: 8px;
  padding: 9px 13px;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  transition: border-color .3s, box-shadow .3s;
}

/* the `hidden` attribute loses to any author `display`, so restore it */
.prompt-box[hidden], .hal[hidden], .terminal[hidden] { display: none; }

.prompt-box.focused {
  border-color: var(--phosphor);
  box-shadow: 0 0 22px -6px var(--phosphor-glow);
}

.prompt-caret { color: var(--phosphor-dim); flex: 0 0 auto; margin-right: 8px; }

.prompt-input {
  color: var(--phosphor-soft);
  white-space: pre-wrap;
  word-break: break-word;
}

.prompt-ghost {
  position: absolute;
  left: 33px;
  top: 9px;
  color: var(--phosphor-dim);
  opacity: .65;
  pointer-events: none;
  transition: opacity .2s;
}
.prompt-box.typed .prompt-ghost { opacity: 0; }

.cursor {
  display: inline-block;
  width: .58em;
  height: 1.05em;
  translate: 0 .18em;
  background: var(--phosphor);
  box-shadow: 0 0 10px var(--phosphor-glow);
  animation: blink 1.05s steps(1) infinite;
}
.prompt-box:not(.focused) .cursor { opacity: .38; animation: none; }

.prompt-hint {
  margin-top: 8px;
  font-size: .82em;
  color: var(--phosphor-dim);
  opacity: 0;
  animation: fade-in .6s ease .4s forwards;
}

kbd {
  font: inherit;
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 0 5px;
  opacity: .9;
}

/* a real input, kept invisible — carries mobile keyboards & IME */
.ghost-field {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 1px; height: 1px;
  border: 0; padding: 0;
  left: 0; top: 0;
}

/* =============================================================
   HAL
   ============================================================= */

.hal {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(20px, 4vmin, 44px);
  opacity: 0;
  visibility: hidden;
  background: radial-gradient(ellipse at center, #0a0503 0%, #030102 70%);
  transition: opacity 1.1s ease, visibility 1.1s;
}

.is-hal .hal { opacity: 1; visibility: visible; }

.hal-plate {
  --lens: clamp(96px, 20vmin, 190px);
  width: calc(var(--lens) * 1.9);
  height: calc(var(--lens) * 1.9);
  border-radius: 14px;
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at 50% 34%, #1c1c1e 0%, #0e0e0f 60%, #050505 100%);
  box-shadow:
    0 0 0 1px rgba(255,255,255,.05),
    0 24px 60px rgba(0,0,0,.8),
    0 0 90px -20px rgba(255,43,23,.35);
}

.hal-lens {
  position: relative;
  width: var(--lens);
  height: var(--lens);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, #1a0402 0%, #050101 72%, #000 100%);
  box-shadow:
    0 0 0 6px #0b0b0c,
    0 0 0 8px #17171a,
    0 0 0 9px rgba(255,255,255,.05),
    0 0 34px rgba(0,0,0,.9) inset;
  display: grid;
  place-items: center;
}

.hal-halo {
  position: absolute;
  inset: -42%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,43,23,.34) 0%, rgba(255,43,23,0) 62%);
  animation: hal-breathe 3.4s ease-in-out infinite;
}

.hal-iris {
  position: absolute;
  width: 62%; height: 62%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, #ff6a4a 0%, var(--hal-red) 34%, #7c0d04 70%, #2a0300 100%);
  box-shadow: 0 0 42px 6px rgba(255,43,23,.6);
  animation: hal-breathe 3.4s ease-in-out infinite;
}

.hal-pupil {
  position: absolute;
  width: 21%; height: 21%;
  border-radius: 50%;
  background: radial-gradient(circle, #fff 0%, #ffd9c8 40%, #ff8a63 100%);
  box-shadow: 0 0 26px 8px rgba(255,180,140,.75);
}

/* the little yellow secondary lamp, off-centre, like the film prop */
.hal-spec {
  position: absolute;
  width: 9%; height: 9%;
  border-radius: 50%;
  top: 21%; left: 25%;
  background: radial-gradient(circle, #fff6d0 0%, #ffbe3d 60%, #6b4700 100%);
  box-shadow: 0 0 16px 3px rgba(255,190,61,.55);
  opacity: .85;
}

.hal-line {
  margin: 0;
  padding: 0 20px;
  max-width: 30ch;
  text-align: center;
  font-size: clamp(14px, 2.3vmin, 22px);
  line-height: 1.6;
  color: #ffd9d2;
  text-shadow: 0 0 14px rgba(255,43,23,.55);
  min-height: 3.2em;
}

/* HAL repeating your question back at you, before the refusal */
.hal-echo {
  display: block;
  margin-bottom: .9em;
  font-size: .72em;
  color: rgba(255, 217, 210, .5);
  text-shadow: none;
  font-style: italic;
}

.hal-say { display: block; }

.hal-line .cursor {
  background: #ffd9d2;
  box-shadow: 0 0 10px rgba(255,43,23,.6);
}

/* terminal recedes while HAL speaks */
.is-hal .terminal { opacity: 0; filter: blur(2px); }

/* =============================================================
   THE BREAK
   ============================================================= */

.is-breaking .screen { animation: shake .42s cubic-bezier(.36,.07,.19,.97) 3; }

.is-breaking .hal {
  animation: hal-die .9s ease-in forwards;
}

/* RGB split + tearing on the terminal (HAL keeps its own death animation) */
.is-breaking .terminal {
  animation: glitch .18s 8;
}

/* dead-pixel blotches, drawn once broken */
.is-broken .glass,
.is-breaking .glass {
  background:
    radial-gradient(circle at 50% 50%, rgba(0,0,0,.55) 0%, rgba(0,0,0,0) 16%),
    radial-gradient(circle at 31% 63%, rgba(0,0,0,.34) 0%, rgba(0,0,0,0) 9%),
    radial-gradient(circle at 68% 34%, rgba(0,0,0,.30) 0%, rgba(0,0,0,0) 7%),
    linear-gradient(105deg, rgba(255,255,255,.045) 0%, rgba(255,255,255,0) 42%);
}

/* =============================================================
   PORTFOLIO
   ============================================================= */

.site {
  position: absolute;
  inset: 0;
  z-index: 4;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(22px, 4.2vmin, 56px) clamp(18px, 4.6vmin, 64px) clamp(30px, 6vmin, 70px);
  color: var(--phosphor-soft);
  font-size: clamp(12.5px, 1.52vmin, 15.5px);
  line-height: 1.75;
  scrollbar-width: thin;
  scrollbar-color: var(--phosphor-dim) transparent;
}
.site::-webkit-scrollbar { width: 8px; }
.site::-webkit-scrollbar-thumb {
  background: var(--phosphor-dim);
  border-radius: 4px;
}

.site[hidden] { display: none; }

.site > * {
  max-width: 74ch;
  margin-inline: auto;
  animation: rise .55s ease both;
}
.site > *:nth-child(2) { animation-delay: .07s; }
.site > *:nth-child(3) { animation-delay: .14s; }
.site > *:nth-child(4) { animation-delay: .21s; }
.site > *:nth-child(5) { animation-delay: .28s; }
.site > *:nth-child(6) { animation-delay: .35s; }

.site-head {
  padding-bottom: 8px;
  display: flex;
  align-items: center;
  gap: clamp(14px, 3vmin, 34px);
  flex-wrap: wrap;
}

.site-id { flex: 1; min-width: 0; }

/* The portrait is sampled at half vertical resolution to suit a monospace
   cell, so it needs line-height 1.2 (twice the 0.6em character advance) to
   come out in proportion. Any other value stretches or squashes the face. */
.portrait {
  flex: 0 0 auto;
  margin: 0;
  font-size: 4px;
  line-height: 1.2;
  white-space: pre;
  color: var(--phosphor-dim);
  text-shadow: 0 0 6px var(--phosphor-glow);
  user-select: none;
}

.site-head h1 {
  margin: 0;
  font-size: clamp(24px, 4.4vmin, 42px);
  letter-spacing: -.01em;
  color: var(--phosphor);
  text-shadow: 0 0 18px var(--phosphor-glow);
}

.tagline {
  margin: 8px 0 0;
  color: var(--phosphor-soft);
  opacity: .9;
}

.sys-note {
  margin: 14px 0 0;
  font-size: .82em;
  color: var(--phosphor-dim);
}
.sys-note span { color: var(--hal-red); opacity: .8; }

.block { margin-top: clamp(30px, 5vmin, 54px); }

.block h2 {
  margin: 0 0 14px;
  font-size: clamp(15px, 2vmin, 19px);
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--phosphor);
  text-shadow: 0 0 12px var(--phosphor-glow);
}
.hash { color: var(--phosphor-dim); margin-right: .5ch; }

.block p { margin: 0 0 12px; }

.job { margin-bottom: 26px; }

.job-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 16px;
  border-bottom: 1px dashed rgba(47,158,99,.4);
  padding-bottom: 5px;
  margin-bottom: 9px;
}

.job-head h3 {
  margin: 0;
  font-size: 1em;
  font-weight: 600;
  color: var(--phosphor);
}

.job-meta {
  font-size: .85em;
  color: var(--phosphor-dim);
  white-space: nowrap;
}

.job ul { margin: 0; padding-left: 1.4em; }
.job li { margin-bottom: 4px; }
.job li::marker { color: var(--phosphor-dim); }

.stack {
  margin: 8px 0 0 !important;
  font-size: .84em;
  color: var(--amber);
  opacity: .8;
}

.skills { display: flex; flex-direction: column; gap: 7px; }
.skill-entry { display: flex; }
.skill-key {
  color: var(--phosphor-dim);
  min-width: 10ch;
}

.cards {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.card {
  border: 1px solid rgba(47,158,99,.42);
  border-radius: 8px;
  padding: 15px 17px;
  background: rgba(20, 46, 31, .22);
  transition: border-color .25s, background .25s, transform .25s;
}

.card:hover {
  border-color: var(--phosphor);
  background: rgba(24, 60, 39, .35);
  transform: translateY(-2px);
}

.card h3 {
  margin: 0 0 8px;
  font-size: 1em;
  color: var(--phosphor);
}

.card p { margin: 0 0 8px; font-size: .95em; }

.links { display: flex; gap: 16px; margin: 10px 0 0 !important; }

a {
  color: var(--phosphor);
  text-decoration: none;
  border-bottom: 1px solid rgba(77,255,159,.35);
  transition: border-color .2s, text-shadow .2s;
}
a:hover {
  border-bottom-color: var(--phosphor);
  text-shadow: 0 0 10px var(--phosphor-glow);
}

.site-foot {
  margin-top: clamp(36px, 6vmin, 64px);
  padding-top: 18px;
  border-top: 1px dashed rgba(47,158,99,.4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  font-size: .9em;
}

.portfolio-footer-btn {
  font: inherit;
  font-size: .95em;
  color: var(--phosphor-dim);
  background: none;
  border: 1px solid rgba(47,158,99,.4);
  border-radius: 6px;
  padding: 5px 11px;
  cursor: pointer;
  transition: color .2s, border-color .2s;
}
.portfolio-footer-btn:hover { color: var(--phosphor); border-color: var(--phosphor); }

/* =============================================================
   SCREEN FX OVERLAYS
   ============================================================= */

.glass, .scanlines, .flicker, .vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* =============================================================
   THE FACE ON THE TUBE
   Sits above HAL and the portfolio, below the glass/scanline overlays so
   it reads as something the CRT is actually displaying.
   ============================================================= */

.photo {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--screen-bg);
  /* makes cqw/cqh below resolve against the screen, not the viewport */
  container-type: size;
  transform-origin: 50% 50%;
  will-change: transform, filter, opacity;
}

.photo[hidden] { display: none; }

/* 84 columns at JetBrains Mono's 0.6em advance is 50.4em wide, and 51 rows
   at line-height 1.2 is 61.2em tall. Sizing off both keeps the whole face on
   screen whichever way the tube is proportioned. */
.photo-art {
  margin: 0;
  font-size: min(calc(100cqw / 52), calc(100cqh / 63));
  line-height: 1.2;
  white-space: pre;
  color: var(--phosphor);
  text-shadow: 0 0 8px var(--phosphor-glow);
}

.photo.crt-on  { animation: crt-on  .62s ease-out both; }
.photo.crt-off { animation: crt-off .70s ease-in  both; }

.glass    { z-index: 7; }
.scanlines{ z-index: 8; }
.flicker  { z-index: 9; }
.vignette { z-index: 10; }

.scanlines {
  background: repeating-linear-gradient(
    180deg,
    rgba(0,0,0,.28) 0px,
    rgba(0,0,0,.28) 1px,
    rgba(0,0,0,0)   1px,
    rgba(0,0,0,0)   3px
  );
  opacity: .55;
  mix-blend-mode: multiply;
}

/* a slow rolling refresh band */
.scanlines::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 22%;
  background: linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.05) 50%, rgba(255,255,255,0) 100%);
  animation: roll 7s linear infinite;
}

.flicker {
  background: rgba(120, 255, 190, .035);
  animation: flicker 5.5s steps(2) infinite;
}

.vignette {
  border-radius: 12px;
  background: radial-gradient(ellipse 92% 86% at 50% 50%, rgba(0,0,0,0) 52%, rgba(0,0,0,.75) 100%);
  box-shadow: 0 0 90px rgba(0,0,0,.7) inset;
}

/* Pinned to the floor of the room rather than sitting in the flex column:
   it toggles on and off mid-intro, and as an in-flow item it re-centred the
   monitor every time it did. --room-chrome already reserves its space. */
.skip {
  position: absolute;
  left: 50%;
  bottom: clamp(6px, 1.6vmin, 18px);
  translate: -50% 0;
  z-index: 1;
  margin: 0;
  font-size: 11px;
  letter-spacing: .1em;
  white-space: nowrap;
  color: #8e8b84;
  transition: opacity .4s;
}
.skip[hidden] { display: none; }

.pong-container {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pong-error {
  text-align: center;
}

/* =============================================================
   KEYFRAMES
   ============================================================= */

@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* A CRT striking: the beam lights a blown-out horizontal line first, the
   line opens vertically into a picture, then the brightness settles. */
@keyframes crt-on {
  0%   { opacity: 0; transform: scale(1, .004); filter: brightness(9) saturate(0); }
  22%  { opacity: 1; transform: scale(1, .004); filter: brightness(9) saturate(0); }
  55%  { opacity: 1; transform: scale(1, 1);    filter: brightness(3.2) saturate(.5); }
  78%  { opacity: 1; transform: scale(1, 1);    filter: brightness(.85) saturate(1); }
  100% { opacity: 1; transform: scale(1, 1);    filter: brightness(1) saturate(1); }
}

/* And dying: the picture collapses to a line, the line pinches to a dot,
   the dot burns out. */
@keyframes crt-off {
  0%   { opacity: 1; transform: scale(1, 1);      filter: brightness(1); }
  38%  { opacity: 1; transform: scale(1, .006);   filter: brightness(6); }
  72%  { opacity: 1; transform: scale(.3, .006);  filter: brightness(10); }
  92%  { opacity: 1; transform: scale(.02, .005); filter: brightness(14); }
  100% { opacity: 0; transform: scale(0, .004);   filter: brightness(16); }
}

@keyframes led-blink { 0%, 60% { opacity: 1; } 61%, 100% { opacity: .25; } }

@keyframes fade-in { to { opacity: 1; } }

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

@keyframes hal-breathe {
  0%, 100% { opacity: .82; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.045); }
}

@keyframes hal-die {
  0%   { opacity: 1; filter: none; }
  40%  { opacity: 1; filter: brightness(2.4) saturate(1.6); }
  70%  { opacity: .5; filter: brightness(.3); transform: scaleY(.7); }
  100% { opacity: 0; filter: brightness(0); transform: scaleY(.02); }
}

@keyframes shake {
  10%, 90% { transform: translate3d(-2px, 1px, 0); }
  20%, 80% { transform: translate3d(4px, -2px, 0); }
  30%, 50%, 70% { transform: translate3d(-6px, 2px, 0); }
  40%, 60% { transform: translate3d(6px, -1px, 0); }
}

@keyframes glitch {
  0%   { transform: none; filter: none; }
  20%  { transform: translate3d(-9px, 0, 0) skewX(-1.2deg);
         filter: drop-shadow(4px 0 0 rgba(255,0,60,.85)) drop-shadow(-4px 0 0 rgba(0,220,255,.85)); }
  40%  { transform: translate3d(7px, 2px, 0);
         filter: drop-shadow(-6px 0 0 rgba(255,0,60,.7)) drop-shadow(6px 0 0 rgba(0,220,255,.7)); }
  60%  { transform: translate3d(-4px, -2px, 0) skewX(1deg);
         filter: invert(1) brightness(1.4); }
  80%  { transform: translate3d(3px, 0, 0);
         filter: drop-shadow(3px 0 0 rgba(255,0,60,.6)) drop-shadow(-3px 0 0 rgba(0,220,255,.6)); }
  100% { transform: none; filter: none; }
}


@keyframes roll {
  from { transform: translateY(-30%); }
  to   { transform: translateY(560%); }
}

@keyframes flicker {
  0%, 92%, 100% { opacity: .30; }
  93%  { opacity: .70; }
  94%  { opacity: .18; }
  95%  { opacity: .62; }
  96%  { opacity: .26; }
}

/* =============================================================
   RESPONSIVE
   ============================================================= */

@media (max-width: 760px) {
  .room { padding: 0; }
  /* the monitor fills the viewport here — there is no room left to see */
  .room::before,
  .room::after { display: none; }
  .monitor {
    /* a 4:3 case would waste most of a phone screen — fill it instead */
    aspect-ratio: auto;
    --case-pad: 14px;
    height: 100%;
    width: 100%;
    border-radius: 0;
  }
  .bezel { border-radius: 10px; padding: 20px; }
  .screen, .vignette { border-radius: 12px; }
  /* nothing on the strip is legible at this size — leave it as bare plastic,
     just wide enough to balance the padding on the left */
  .chin {
    width: var(--case-pad);
    padding: 0;
    gap: 0;
  }
  .chin > * { display: none; }
  .skip { display: none; }
  .job-head { flex-direction: column; }
  .job-meta { white-space: normal; }
  /* the 84-column portrait can't get small enough to sit beside the name
     on a phone without becoming illegible — stack it above instead */
  .site-head { flex-direction: column; align-items: flex-start; gap: 10px; }
  .portrait { font-size: 4px; }
}

@media (max-height: 520px) {
  .monitor { aspect-ratio: auto; height: 100%; }
}

/* =============================================================
   REDUCED MOTION — keep the story, drop the seizure risk
   ============================================================= */

@media (prefers-reduced-motion: reduce) {
  .monitor { animation: none; }
  .flicker, .scanlines::after { animation: none; }
  .flicker { opacity: .25; }
  .cursor, .led { animation: none; }
  /* the JS clamps its waits under reduced motion, so the fixed-duration
     collapse would run on past the sequence — just show it and cut */
  .photo.crt-on { animation: none; }
  .photo.crt-off { animation: none; opacity: 0; }
  .hal-halo, .hal-iris { animation: none; }
  .is-breaking .screen,
  .is-breaking .terminal,
  .is-breaking .site,
  .is-breaking .hal { animation: none; }
  .is-breaking .hal { opacity: 0; transition: opacity .5s; }
  .site > * { animation: none; opacity: 1; transform: none; }
  .card:hover { transform: none; }
}
