/* ============================================================
   PORTFOLIO — STYLE.CSS  |  Light Theme Only
   ============================================================ */

/* ── LOCAL FONTS ────────────────────────────────────────── */
@font-face {
  font-family: 'Type Machine';
  src: url('/assets/fonts/type-machine-latin.woff2') format('woff2'),
       url('/assets/fonts/type-machine.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* Home-critical display faces are served locally. This keeps the exact
   typography while removing the external stylesheet and font handshakes
   from the first visit. */
@font-face {
  font-family: 'VT323';
  src: url('/assets/fonts/vt323-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Playfair Display';
  src: url('/assets/fonts/playfair-display-normal-600-700-latin.woff2') format('woff2');
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Playfair Display';
  src: url('/assets/fonts/playfair-display-italic-500-latin.woff2') format('woff2');
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}

/* ── ROCKWELL + GEIST (projects page) ─────────────────────────────
   Rockwell uses the extracted webfont in /assets/fonts. Geist uses the
   bundled variable font in /Fonts so every requested weight resolves
   without a chain of failed font requests. */
/* Rockwell Regular, extracted from Fonts/Rockwell.ttc (face 0). The .ttc
   itself is a TrueType Collection — browsers cannot load one, so the
   single Regular face was pulled out and converted. Regular only: the
   display type is set at weight 400 by design, and declaring a range
   here would let the browser synthesise a fake bold. */
@font-face {
  font-family: 'Rockwell';
  src: url('/assets/fonts/rockwell-regular.woff2') format('woff2'),
       url('/assets/fonts/rockwell-regular.ttf')   format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Geist';
  src: url('/Fonts/GeistVF-BF6569491f13184_2.ttf') format('truetype');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ── CUSTOM PROPERTIES ─────────────────────────────────── */
:root {
  --bg:            #FBFBFB;
  --fg:            #2D2D2D;
  --fg-dim:        rgba(17, 17, 17, 0.25);
  --fg-dimmer:     rgba(17, 17, 17, 0.08);
  --accent:        #22c55e;
  --accent-dim:    rgba(34, 197, 94, 0.10);
  --border:        rgba(17, 17, 17, 0.10);
  --border-strong: rgba(17, 17, 17, 0.20);

  /* Typography */
  /* Big display type — the name lockup, the 01/02 numerals, the edge
     labels and every hero title. Rockwell first for machines that have
     it (it ships with MS Office, not with macOS), then Rokkitt, which
     is a Rockwell-derived slab loaded from Google so the look holds up
     where Rockwell is missing — it is absent on this machine, so the
     webfont is what actually renders here. */
  --font-slab:    'Rockwell', 'Rockwell Nova', Georgia, serif;
  --font-display: var(--font-slab);
  --font-name:    var(--font-slab);
  --font-ui:      'Type Machine', 'Space Grotesk', 'Helvetica Neue', Arial, sans-serif;

  /* Name — tight line-height */
  --name-fs:  clamp(110px, 15vw, 220px);
  --name-lh:  0.82;
  /* The slot that clips each letter used to be exactly --name-lh (0.82)
     tall. At line-height 0.82 the glyphs are taller than their own line
     box, so `overflow:hidden` on .name-slot shaved the tops of the caps
     clean off. The slot now gets the full em box; --name-lh still drives
     the tight optical stacking, and --name-shift re-centres the letter
     inside the taller slot so the lockup sits exactly where it did. */
  --name-h:   calc(var(--name-fs) * 1.0);
  --name-shift: calc(var(--name-fs) * -0.09);

  /* Easing */
  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out:    cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --ease-bounce:    cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ── PAGE TRANSITION — panels + pixel waveform ──────────── */
#txOverlay {
  position: fixed;
  inset: 0;
  /* Below CRT frame (9950) so transitions happen inside the TV screen */
  z-index: 9900;
  visibility: hidden;
  pointer-events: none;
  overflow: hidden;
}

/* Scanlines on top of transition panels — very subtle */
#txOverlay::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 10;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    transparent              0px,
    transparent              3px,
    rgba(0, 0, 0, 0.03)      3px,
    rgba(0, 0, 0, 0.03)      4px
  );
}



/* ── panels layer (background only, zooms) ── */
.tx-panels {
  position: absolute;
  inset: 0;
  display: flex;
}
.tx-p {
  height: 100%;
  flex-shrink: 0;
  background: #1a1614;
}
.tx-p--l, .tx-p--r { flex: 0 0 27%; }
.tx-p--c {
  flex: 0 0 46%;
  transform-origin: 50% 50%;
}

/* ── waveform layer — pixel-matrix audio bars, centred ── */
.tx-wave {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 3;
  opacity: 0;
}
.tx-wave-canvas {
  display: block;
  image-rendering: pixelated;
  filter: drop-shadow(0 0 14px rgba(255, 255, 255, 0.18));
}

/* ── RESET ─────────────────────────────────────────────── */
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

html {
  height: 100%;
  background: #1a1614; /* Dark fallback — hides browser's blank frame during page transitions */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Hide preloader before first render when coming from internal nav */
html.skip-preloader #preloader {
  display: none !important;
}

body {
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-ui);
  cursor: none;
}

img {
  display: block;
  max-width: 100%;
  user-select: none;
  -webkit-user-drag: none;
}

a { text-decoration: none; color: inherit; }

/* ── BACKGROUND ─────────────────────────────────────────── */
.bg-layer {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.bg-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.fluid-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.bg-noise {
  position: absolute;
  inset: 0;
  opacity: 0.5;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 300px 300px;
}

/* ── MENU DOTS (CREATIVE / MORPHING) ───────────────────── */
.menu-dots {
  position: fixed;
  top: 38px;
  right: 38px;
  z-index: 200;
  width: 48px;
  height: 48px;
  background: none;
  border: none;
  cursor: none;
  padding: 0;
}

.menu-dots span {
  position: absolute;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--fg);
  display: block;
  transition:
    left  0.75s var(--ease-out-quint),
    top   0.75s var(--ease-out-quint),
    transform 0.3s var(--ease-bounce),
    opacity 0.3s;
  animation: dotPulse 2.4s ease-in-out infinite;
}

@keyframes dotPulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.22; }
}

.menu-dots span:nth-child(1) { animation-delay: 0.00s; }
.menu-dots span:nth-child(2) { animation-delay: 0.27s; }
.menu-dots span:nth-child(3) { animation-delay: 0.53s; }
.menu-dots span:nth-child(4) { animation-delay: 0.80s; }
.menu-dots span:nth-child(5) { animation-delay: 1.07s; }
.menu-dots span:nth-child(6) { animation-delay: 1.33s; }
.menu-dots span:nth-child(7) { animation-delay: 1.60s; }
.menu-dots span:nth-child(8) { animation-delay: 1.87s; }
.menu-dots span:nth-child(9) { animation-delay: 2.13s; }

.menu-dots.fluid-over span {
  background: white;
  transition: background 0.3s ease, left 0.75s var(--ease-out-quint), top 0.75s var(--ease-out-quint), transform 0.3s var(--ease-bounce), opacity 0.3s;
}

.menu-dots:hover span {
  animation-play-state: paused;
  opacity: 1 !important;
}
.menu-dots:hover span:nth-child(odd)  { transform: scale(1.8); }
.menu-dots:hover span:nth-child(even) { transform: scale(1.2); }
.menu-dots:hover span:nth-child(5)    { transform: scale(2.5); }

/* ── SIDE LABELS ────────────────────────────────────────── */
.side {
  position: fixed;
  top: 65%;
  transform: translateY(-50%);
  z-index: 50;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: clamp(46px, 3.4vw, 70px);
  cursor: none;
  text-decoration: none;
  color: inherit;
  opacity: 0;
  animation: sideReveal 0.8s cubic-bezier(0.22, 1, 0.36, 1) 2.2s both;
  transition: scale 0.6s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.6s ease;
}

.side--left  {
  left: 64px;
  transform-origin: left center;
  animation-name: sideRevealLeft;
}

.side--right {
  right: 64px;
  transform-origin: right center;
  animation-name: sideRevealRight;
}

@keyframes sideRevealLeft {
  from { opacity: 0; transform: translateX(-50px) translateY(-50%); }
  to   { opacity: 1; transform: translateX(0)     translateY(-50%); }
}

@keyframes sideRevealRight {
  from { opacity: 0; transform: translateX(50px) translateY(-50%); }
  to   { opacity: 1; transform: translateX(0)    translateY(-50%); }
}

/* Small vertical label */
.side-text {
  writing-mode: vertical-rl;
  /* stays Type Machine — only the numerals beside it are slab */
  font-family: var(--font-ui);
  font-size: 24px;
  font-weight: 600;
  letter-spacing: 0.16em;
  color: #111;
  white-space: nowrap;
  transition: color 0.5s var(--ease-out-quint), text-shadow 0.5s var(--ease-out-quint);
}

.side--left .side-text {
  transform: rotate(180deg);
}

.side--right .side-text {
  letter-spacing: 0.10em;
  margin-top: 2px;
}

.side--right .side-arrow {
  position: relative;
  top: 4px;
}

.side:hover .side-text {
  color: rgba(17, 17, 17, 0.55);
}

/* Huge decorative number */
.side-nr {
  writing-mode: vertical-rl;
  font-family: var(--font-display);
  font-size: clamp(100px, 13vw, 360px);
  font-weight: 600;
  line-height: 0.88;
  letter-spacing: -0.03em;
  color: #111111;
  opacity: 0.07;
  white-space: nowrap;
  pointer-events: none;
  transition: color 0.8s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1), text-shadow 0.8s cubic-bezier(0.22, 1, 0.36, 1), transform 0.8s cubic-bezier(0.22, 1, 0.36, 1);
  user-select: none;
}

.side--left .side-nr  { transform: rotate(180deg); margin-top: -4px; }
.side--right .side-nr { transform: rotate(0deg); }

.side:hover .side-nr {
  color: rgba(17, 17, 17, 0.11);
}

/* ── SLIDE GROUP ─────────────────────────────────────────── */
.slide-group {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 10;
  will-change: transform;
}

/* ── PORTRAIT ────────────────────────────────────────────── */
.portrait-section {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  pointer-events: none;
  height: 95vh;
  width: auto;
  display: flex;
  align-items: flex-end;
  -webkit-mask-image: linear-gradient(to top, transparent 0%, black 18%);
  mask-image: linear-gradient(to top, transparent 0%, black 18%);
  animation: portraitReveal 1.2s cubic-bezier(0.22, 1, 0.36, 1) 0s both;
}

@keyframes portraitReveal {
  from {
    opacity: 0.82;
    transform: translateX(-50%) translateY(32px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}

/* Keep the entrance but let the portrait count as painted immediately.
   The old fully transparent 1.2s rise delayed LCP even after the 29KB mobile
   image had already downloaded. */
.portrait-section { animation-duration: 0.42s; }

.portrait-frame {
  position: relative;
  height: 100%;
  width: auto;
}

.portrait-base {
  position: relative;
  z-index: 1;
  height: 100%;
  width: auto;
  max-width: none;
  object-fit: contain;
  object-position: bottom center;
}

.portrait-illustration {
  position: absolute;
  inset: 0;
  z-index: 2;
  height: 100%;
  width: 100%;
  object-fit: contain;
  object-position: bottom center;
  visibility: hidden;
}

.illustration-canvas {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* ── NAME (SIVIN / KOUSHIP) ──────────────────────────────── */
.name-section {
  position: absolute;
  /* Clears the CRT bezel. The barrel bulges inward to ~23px at the bottom
     centre (MC 38 / MM 8 in the per-page clip-path script) and the frame
     carries a 4px blur on top of that, so the old 15px left the feet of
     the letters sitting under the black. */
  bottom: clamp(18px, 2.6vw, 36px);
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  justify-content: center;
  pointer-events: none;
  overflow: visible;

  animation: nameReveal 1.0s cubic-bezier(0.22, 1, 0.36, 1) 1.2s both;
}

@keyframes nameReveal {
  from { opacity: 0; transform: translateY(60px); }
  to   { opacity: 1; transform: translateY(0); }
}

.name-display {
  display: flex;
  align-items: flex-end;
  gap: 0;
  line-height: var(--name-lh);
  position: relative; /* YENİ EKLENDİ: Grain filtresi için kilit */
}


/* Individual letter slot */
.name-slot {
  /* --name-h is font-size x 0.82 (the line-height), which is SHORTER than
     the capitals it has to contain — with overflow:hidden that sliced the
     tops off every letter of the name. The mask has to stay for the
     letter-reveal, so give it headroom instead and bottom-align the glyph
     inside: .name-display is align-items:flex-end, so the extra height
     grows upward and the baseline does not move. */
  height: calc(var(--name-h) * 1.3);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  position: relative;
  flex-shrink: 0;
  transition: width 0.35s var(--ease-out-quint), opacity 0.25s;
}

/* Tracking -127 (Adobe units are 1/1000 em) as a gap between letters, so
   each slot keeps its full advance and nothing gets clipped. Sibling
   selector so the run isn't offset by a trailing negative margin. */
.name-slot + .name-slot {
  margin-left: calc(var(--name-fs) * -0.127);
}

.name-slot.exiting {
  opacity: 0;
  width: 0 !important;
}

/* The spinning reel */
.name-reel {
  display: flex;
  flex-direction: column;
  will-change: transform;
}

/* Individual char on the reel */
.name-char {
  font-family: var(--font-name);
  font-size: var(--name-fs);
  /* Rockwell is supplied as Regular only — asking for 900 would make the
     browser synthesise a fake bold instead of using the real face */
  font-weight: 400;
  /* Tracking is NOT set here. letter-spacing trims each character's
     advance, but the glyph ink stays the same width — and since every
     letter sits in a .name-slot with overflow:hidden, that shaved the
     right edge off each one. The -127 tracking is applied as a negative
     gap between slots instead (see .name-slot + .name-slot). */
  letter-spacing: normal;
  line-height: var(--name-lh);
  height: var(--name-h);
  /* compensate for the taller slot — see --name-shift */
  margin-top: var(--name-shift);
  color: var(--fg);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  white-space: nowrap;
  padding: 0 0.008em;
}

/* ── CUSTOM CURSOR ───────────────────────────────────────── */
.cursor {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 10003;
}

.cursor-dot {
  position: absolute;
  left: -200px; top: -200px; /* JS yazana kadar ekran dışında */
  width: 2px;
  height: 12px;
  border-radius: 0;
  background: #fff;
  transform: translate(-50%, -50%);
  will-change: left, top;
  mix-blend-mode: difference;
}

.cursor-dot::before {
  content: '';
  position: absolute;
  width: 12px;
  height: 2px;
  background: #fff;
  border-radius: 0;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

/* Contact page uses UFO cursor — hide default cursor elements */
body.page-contact .cursor-dot,
body.page-contact .cursor-ring {
  display: none;
}

.cursor-ring {
  position: absolute;
  left: -200px; top: -200px; /* JS yazana kadar ekran dışında */
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 3px solid #fff;
  transform: translate(-50%, -50%);
  will-change: left, top;
  mix-blend-mode: difference;
  transition:
    width  0.3s var(--ease-bounce),
    height 0.3s var(--ease-bounce);
}

/* cursor ring sabit boyut — zone değişiminde büyüyüp küçülme yok */

/* ── PAGE INIT ──────────────────────────────────────────── */
body:not(.js-ready) .name-section,
body:not(.js-ready) .portrait-section {
  visibility: hidden;
}

/* ── HOME NAME — DESKTOP ONLY, HIDDEN ─────────────────────────
   The landing carries no name on a wide viewport: neither the big
   SIVIN / KOUSHIP lockup above the bezel nor the nav's own swapping
   label. The portrait is the whole page.

   Deliberately scoped to min-width:769px — the mirror of the 768px
   breakpoint mobile-scroll.js gates `has-ms` on — so the phone layout
   is untouched and keeps showing its own .ms-name lockup.

   `visibility` rather than `display` for .name-section, for the same
   reason mobile-scroll.css gives: main.js sizes the reels by appending
   probe elements into #nameDisplay and reading getBoundingClientRect(),
   and a display:none ancestor zeroes every one of those measurements.
   Hidden this way its maths still runs against real widths. */
@media (min-width: 769px) {
  body.page-index .name-section { visibility: hidden !important; }
  body.page-index #navIndexLabel { display: none; }
}

/* ── TRANSITION WORDS — MOBILE ───────────────────────────── */
@media (max-width: 768px) {
}

/* ── RESPONSIVE ──────────────────────────────────────────── */
@media (max-width: 768px) {
  :root { --name-fs: clamp(100px, 24vw, 160px); }

  /* left stays 50% — matches the base rule's translateX(-50%), so the
     box is centered on the viewport. It was 55% here, a flat 5vw
     rightward shift with no compensating factor anywhere else, which
     visibly pushed the portrait off-center on every phone. */
  .portrait-section { height: 70vh; left: 50%; }
  .menu-dots        { top: 16px; right: 18px; }
  .side-nr          { display: none; }
  .side--left       { left: 24px; }
  .side--right      { right: 24px; }
  .slide-group      { transform: none !important; }
  /* bezel is ~8px at the bottom centre here, so 8px sat exactly on it */
  .name-section     { justify-content: center; left: 0; right: 0; bottom: 18px; }
  .name-display     { justify-content: center; }
}

@media (max-width: 480px) {
  :root { --name-fs: clamp(80px, 22vw, 120px); }

  .portrait-section { height: 65vh; }
  .side-nr          { font-size: clamp(50px, 10vw, 90px); }
  .side-text        { font-size: 11px; }
}

/* ── TV PRELOADER ────────────────────────────────────────── */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: #060606;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.6s ease, visibility 0.6s ease;
}

.preloader.loaded {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* TV outer — fills entire preloader; barrel clip-path via JS creates CRT shape */
.tv-outer {
  position: absolute;
  inset: 0;
  background: #050505;
  padding: 8px;
  filter: drop-shadow(0 6px 40px rgba(0, 0, 0, 0.9));
}

/* Subtle gray bevel — visible at barrel midpoints (element edge = screen edge there) */
.tv-outer::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(160, 160, 160, 0.20) 0%, transparent 22px),
    linear-gradient(to top,    rgba(130, 130, 130, 0.14) 0%, transparent 16px),
    linear-gradient(to right,  rgba(145, 145, 145, 0.17) 0%, transparent 20px),
    linear-gradient(to left,   rgba(145, 145, 145, 0.17) 0%, transparent 20px);
}

/* TV screen inner */
.tv-screen {
  width: 100%;
  height: 100%;
  border-radius: clamp(14px, 2vw, 36px);
  overflow: hidden;
  position: relative;
  background: #000;
}

/* Inner layer */
.tv-inner {
  position: absolute;
  inset: 0;
}

/* SMPTE bars — top 75% */
.tv-bars {
  position: absolute;
  inset: 0 0 25% 0;
  display: flex;
}

.tv-bar       { flex: 1; height: 100%; }
.tv-bar--w    { background: #ffffff; }
.tv-bar--y    { background: #ffff00; }
.tv-bar--c    { background: #00ffff; }
.tv-bar--g    { background: #00ff00; }
.tv-bar--m    { background: #ff00ff; }
.tv-bar--r    { background: #ff0000; }
.tv-bar--b    { background: #0000ff; }

/* Bottom strip */
.tv-bars-bottom {
  position: absolute;
  inset: 75% 0 0 0;
  display: flex;
}

.tv-bar-b     { flex: 1; height: 100%; }
.tv-bar-b--1  { background: #0000bb; }
.tv-bar-b--2  { background: #131313; }
.tv-bar-b--3  { background: #bb00bb; }
.tv-bar-b--4  { background: #131313; }
.tv-bar-b--5  { background: #00bbbb; }
.tv-bar-b--6  { background: #131313; }
.tv-bar-b--7  { background: #eeeeee; }

/* Barcode patterns left/right */
.tv-barcode {
  position: absolute;
  top: 0;
  bottom: 25%;
  width: 17%;
  z-index: 2;
  background: repeating-linear-gradient(
    to right,
    #000  0px, #000  5px,
    #fff  5px, #fff  9px,
    #000  9px, #000 13px,
    #fff 13px, #fff 15px,
    #000 15px, #000 21px,
    #fff 21px, #fff 25px,
    #000 25px, #000 29px,
    #fff 29px, #fff 31px,
    #000 31px, #000 38px
  );
  opacity: 0.88;
}

.tv-barcode--left  { left: 0; }
.tv-barcode--right { right: 0; }

/* Center content */
.tv-center {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}

/* Black panel wrapping text + bar — fixed proportional size */
.tv-panel {
  background: #000;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: clamp(12px, 2vw, 36px) clamp(14px, 2.8vw, 48px) clamp(18px, 2.4vw, 28px);
  gap: clamp(8px, 1.2vw, 16px);
  width: clamp(220px, 36vw, 520px);
  flex-shrink: 0;
}

.tv-msg {
  color: #fff;
  font-family: 'VT323', monospace;
  font-weight: 400;
  font-size: clamp(1.5rem, 4vw, 4.8rem);
  letter-spacing: 0.08em;
  text-align: center;
  line-height: 1.05;
  text-transform: uppercase;
  text-shadow: 0 0 10px rgba(255, 255, 255, 0.22);
}

/* Bar row — height = fill height + 2 × (gap + border) = 34 + 18 = 52px */
.tv-panel-bar {
  position: relative;
  height: 52px;
}

/* Fill area — absolutely centered; ::before draws the stroke frame outside */
.tv-progress {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: clamp(160px, 26vw, 380px);
  height: 34px;
  overflow: hidden;
}

/* Stroke: 8px gap + 1px border around the fill area */
.tv-progress::before {
  content: '';
  position: absolute;
  inset: -9px;
  border: 1px solid rgba(255, 255, 255, 0.38);
  pointer-events: none;
}

/* Segments width set dynamically by JS */
.tv-progress-fill {
  height: 100%;
  width: 0%;
}

/* Pct hidden — bar stroke used instead */
.tv-pct {
  display: none;
}

/* ── TV SKIP HINT ────────────────────────────────────────── */
.tv-skip-hint {
  text-align: center;
  opacity: 0;
  transition: opacity 0.7s ease;
}
.tv-skip-hint.is-visible { opacity: 1; }
.tv-skip-hint.is-pulsing {
  animation: tvSkipPulse 2s ease-in-out infinite;
}
.tv-skip-desktop,
.tv-skip-mobile {
  font-family: 'VT323', monospace;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  display: none;
}
.tv-skip-desktop {
  font-size: 24px;
  color: #facc15;
}
.tv-skip-mobile {
  font-size: 28px;
  color: #facc15;
}
@media (pointer: fine) {
  .tv-skip-desktop { display: block; }
}
@media (pointer: coarse) {
  .tv-skip-mobile { display: block; }
}
@keyframes tvSkipPulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.35; }
}

/* Scanlines */
.tv-scanlines {
  position: absolute;
  inset: 0;
  z-index: 15;
  background: repeating-linear-gradient(
    to bottom,
    transparent              0px,
    transparent              2px,
    rgba(0, 0, 0, 0.13)      2px,
    rgba(0, 0, 0, 0.13)      4px
  );
  pointer-events: none;
}

/* Grain canvas */
.tv-grain-canvas {
  position: absolute;
  inset: 0;
  z-index: 16;
  width: 100%;
  height: 100%;
  opacity: 0.045;
  pointer-events: none;
  image-rendering: auto;
}

/* Pixel glitch canvas — z-index 14 so snow covers panel during burst */
.tv-glitch-canvas {
  position: absolute;
  inset: 0;
  z-index: 14;
  width: 100%;
  height: 100%;
  pointer-events: none;
  image-rendering: pixelated;
}

/* CRT vignette */
.tv-vignette {
  position: absolute;
  inset: 0;
  z-index: 18;
  pointer-events: none;
  background: radial-gradient(
    ellipse at center,
    transparent 55%,
    rgba(0, 0, 0, 0.65) 100%
  );
}

/* Scanner lines — horizontal bright lines sweeping top → bottom continuously */
.tv-scanner-lines {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  overflow: hidden;
}
.tv-scanner-lines span {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 1.5px;
  background: rgba(255, 255, 255, 0.12);
  mix-blend-mode: multiply;
  box-shadow:
    0  3px 0 rgba(255, 255, 255, 0.06),
    0  6px 0 rgba(255, 255, 255, 0.03);
  will-change: transform;
  animation: tvScanDown var(--dur, 3s) linear infinite;
  animation-delay: var(--del, 0s);
}
@keyframes tvScanDown {
  from { transform: translateY(-10px); }
  to   { transform: translateY(calc(100vh + 10px)); }
}

/* Inner screen edge highlight — glass/CRT light reflection on all edges */
.tv-inner-glow {
  position: absolute;
  inset: 0;
  z-index: 17;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(255, 255, 255, 0.08) 0%, transparent 22%),
    linear-gradient(to top,    rgba(255, 255, 255, 0.05) 0%, transparent 18%),
    linear-gradient(to right,  rgba(255, 255, 255, 0.06) 0%, transparent 18%),
    linear-gradient(to left,   rgba(255, 255, 255, 0.06) 0%, transparent 18%);
}

/* Chaos blocks */
.tv-chaos { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.tv-cb    { position: absolute; }

/* Large pink corner blocks */
.tv-cb-1  { top: 0;    left: 0;     width: 9%;    height: 48%; background: #ff7aff; }
.tv-cb-2  { top: 0;    right: 0;    width: 9%;    height: 48%; background: #ff7aff; }
/* Dark flanking barcodes */
.tv-cb-3  { top: 0;    left: 9%;    width: 4.5%;  height: 48%; background: #0d0d0d; }
.tv-cb-4  { top: 0;    right: 9%;   width: 4.5%;  height: 48%; background: #0d0d0d; }
/* Blue accent blocks top inner */
.tv-cb-5  { top: 0;    left: 13.5%; width: 2.5%;  height: 24%; background: #0033dd; }
.tv-cb-6  { top: 0;    right: 13.5%;width: 2.5%;  height: 24%; background: #0033dd; }
/* Bottom blue corner blocks */
.tv-cb-7  { bottom: 0; left: 0;     width: 9%;    height: 28%; background: #0033cc; }
.tv-cb-8  { bottom: 0; right: 0;    width: 9%;    height: 28%; background: #0033cc; }
/* Magenta scattered bottom */
.tv-cb-9  { bottom: 28%; left: 3.5%; width: 4.5%; height: 13%; background: #ff00cc; }
.tv-cb-10 { bottom: 0;   left: 9%;   width: 4%;   height: 13%; background: #ff44bb; }
/* Yellow accents */
.tv-cb-11 { bottom: 29%; right: 3%;  width: 3%;   height: 9%;  background: #ffff00; }
.tv-cb-12 { bottom: 0;   right: 9%;  width: 2.5%; height: 11%; background: #ffee00; }
/* Thin cyan vertical markers */
.tv-cb-13 { top: 28%; left: 21%;    width: 3px;   height: 34%; background: #00ffff; }
.tv-cb-14 { top: 22%; right: 19%;   width: 3px;   height: 40%; background: #00ffff; }
/* Horizontal cyan stripe mid */
.tv-cb-15 { top: 67%; left: 17%;    width: 20%;   height: 2px; background: #00ffff; }
/* Small stray mid blocks */
.tv-cb-16 { top: 13%;  left: 36%;   width: 3%;    height: 8%;  background: #ff0000; }
.tv-cb-17 { top: 7%;   right: 31%;  width: 2%;    height: 6%;  background: #ffff00; }
.tv-cb-18 { top: 50%;  left: 14%;   width: 4.5%;  height: 15%; background: #0d0d0d; }
.tv-cb-19 { top: 44%;  right: 12%;  width: 3.5%;  height: 19%; background: #0d0d0d; }
/* White stripe accent */
.tv-cb-20 { bottom: 30%; left: 23%;  width: 1.5%;  height: 22%; background: rgba(255,255,255,0.75); }
/* Extra chaos — upper area */
.tv-cb-21 { top: 0;     left: 16%;   width: 2%;    height: 12%; background: #ff0000; }
.tv-cb-22 { top: 0;     right: 16%;  width: 1.5%;  height: 17%; background: #00ff00; }
/* Mid column accents */
.tv-cb-23 { top: 52%;   left: 0;     width: 9%;    height: 8%;  background: #ffff00; }
.tv-cb-24 { top: 60%;   right: 0;    width: 9%;    height: 7%;  background: #ff00ff; }
/* Small white dashes */
.tv-cb-25 { top: 22%;   left: 31%;   width: 1.5%;  height: 6%;  background: #fff; }
.tv-cb-26 { top: 38%;   right: 29%;  width: 1%;    height: 9%;  background: #fff; }
/* Bottom inner accents */
.tv-cb-27 { bottom: 0;  left: 13.5%; width: 3%;    height: 9%;  background: #0000ff; }
.tv-cb-28 { bottom: 0;  right:13.5%; width: 2.5%;  height: 7%;  background: #ff0000; }
/* Thin horizontal stripes mid */
.tv-cb-29 { top: 46%;   left: 17%;   width: 22%;   height: 2px; background: rgba(255,255,255,0.6); }
.tv-cb-30 { top: 40%;   right: 20%;  width: 14%;   height: 2px; background: rgba(255,0,255,0.85); }

/* Cyan crosshairs */
.tv-cross {
  position: absolute;
  width: clamp(14px, 2.2vw, 26px);
  height: clamp(14px, 2.2vw, 26px);
  z-index: 4;
}
.tv-cross::before,
.tv-cross::after {
  content: '';
  position: absolute;
  background: #00ffff;
}
.tv-cross::before { top: 50%; left: 0; width: 100%; height: 1.5px; transform: translateY(-50%); }
.tv-cross::after  { left: 50%; top: 0; height: 100%; width: 1.5px; transform: translateX(-50%); }

.tv-cross-1 { bottom: 34%; left: 20%; }
.tv-cross-2 { bottom: 29%; right: 18%; }
.tv-cross-3 { top: 18%;    left: 44%; }

/* ── BOOT SEQUENCE ───────────────────────────────────────── */
body.boot-pending .portrait-section,
body.boot-pending .name-section {
  opacity: 0 !important;
  animation: none !important;
}

body.boot-pending .side {
  opacity: 0 !important;
  animation: none !important;
}

/* Mobile */
@media (max-width: 768px) {
  .tv-screen {
    border-radius: clamp(10px, 1.8vw, 24px);
  }
  .tv-barcode {
    display: none;
  }
  .tv-msg {
    font-size: clamp(2rem, 8vw, 3.5rem);
    letter-spacing: 0.06em;
  }
  .bios-line--logo {
    font-size: 22px !important;
    letter-spacing: 0.1em;
  }
  /* Loading bar — smaller on mobile; gap 5px → inset -6px */
  .tv-panel-bar {
    height: 28px;
  }
  .tv-progress {
    height: 16px;
  }
  .tv-progress::before {
    inset: -6px;
  }
}

/* ── MOBILE: cursor kapalı ───────────────────────────────── */
@media (max-width: 768px) {
  body, a, button { cursor: auto; }
  .cursor, .cursor-dot, .cursor-ring { display: none !important; }
  /* The per-page clip-path script drops the bezel to MC 12 / MM 4 here,
     leaving it only ~8px thick at the edge midpoints — the desktop blur
     would spread that until the frame reads as a smudge. */
  :root { --tv-edge-blur: 3px; }
}

/* ── TOUCH DEVICES: custom cursor kapalı ────────────────── */
@media (pointer: coarse) {
  body, a, button { cursor: auto; }
  .cursor, .cursor-dot, .cursor-ring { display: none !important; }
}

/* ── REDUCED MOTION ──────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }

  /* Decorative looping scroll animations: stop and reset position */
  .clients-track,
  .marquee-col-track {
    animation: none !important;
    transform: none !important;
  }

  /* Magnetic hover image has no purpose without motion */
  .magnetic-img {
    display: none !important;
  }

  .side--left .side-text,
  .side--right .side-text {
    animation: none !important;
  }
}

/* ── SCREEN READER ONLY ──────────────────────────────────── */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* ── SKIP TO CONTENT ─────────────────────────────────────── */
.skip-to-content {
  position: fixed;
  top: -100px;
  left: 20px;
  z-index: 99999;
  background: #ef4444;
  color: #fff;
  font-family: 'Type Machine', 'Space Grotesk', sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 10px 20px;
  border-radius: 2px;
  transition: top 0.2s ease;
}
.skip-to-content:focus {
  top: 20px;
}

/* ── FOCUS STYLES ────────────────────────────────────────── */
:focus-visible {
  outline: 2px solid #ef4444;
  outline-offset: 3px;
  border-radius: 2px;
}
:focus:not(:focus-visible) {
  outline: none;
}

/* Projects sayfası — hem kırmızı hem beyaz bölümde görünür focus */
body.page-uxui :focus-visible {
  outline: 2px solid #1c1917;
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.75);
}
body.page-uxui .skip-to-content {
  background: #1c1917;
  color: #fff;
}

/* Artworks — sarı outline + beyaz halo */
body.page-artworks :focus-visible {
  outline: 2px solid #facc15;
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.75);
}
body.page-artworks .skip-to-content {
  background: #facc15;
  color: #1d4ed8;
}

/* Contact — kırmızı outline + beyaz halo */
body.page-contact :focus-visible {
  outline: 2px solid #ef4444;
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.75);
}
body.page-contact .skip-to-content {
  background: #ef4444;
  color: #fff;
}

/* Ana sayfa — mavi outline + kırmızı halo */
body.page-index :focus-visible {
  outline: 2px solid #1d4ed8;
  box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.75);
}
body.page-index .skip-to-content {
  background: #1d4ed8;
  color: #fff;
}

/* ============================================================
   SIDEBAR HOVER (BÜYÜME VE KAYBOLMA) EFEKTLERİ - SABİT KONUM
   ============================================================ */

/* FARE SOLA (UX/UI DESIGN) GİDİNCE */
body.cursor-left .side--left {
  scale: 1.15;
  opacity: 1;
}
body.cursor-left .side--left .side-nr {
  writing-mode: horizontal-tb;
  transform: rotate(720deg) scale(1.15);
  color: #ef4444;
  opacity: 1;
  text-shadow: 0 0 28px rgba(239, 68, 68, 0.45), 0 0 60px rgba(239, 68, 68, 0.15);
  transition: color 0.8s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1), text-shadow 0.8s cubic-bezier(0.22, 1, 0.36, 1), transform 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}
body.cursor-left .side--left .side-text {
  color: #b91c1c;
  text-shadow: 0 0 18px rgba(185, 28, 28, 0.50), 0 0 40px rgba(185, 28, 28, 0.18);
}
body.cursor-left .side--right {
  opacity: 0.10 !important;
  scale: 0.95;
  pointer-events: none;
}

/* FARE SAĞA (ILLUSTRATION) GİDİNCE */
body.cursor-right .side--right {
  scale: 1.15;
  opacity: 1;
}
body.cursor-right .side--right .side-nr {
  writing-mode: horizontal-tb;
  transform: rotate(360deg) scale(1.15);
  color: #ffd633;
  opacity: 1;
  text-shadow: 0 0 28px rgba(255, 214, 51, 0.55), 0 0 60px rgba(255, 214, 51, 0.20);
  transition: color 0.8s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1), text-shadow 0.8s cubic-bezier(0.22, 1, 0.36, 1), transform 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}
body.cursor-right .side--right .side-text {
  color: #ffd633;
  text-shadow: 0 0 18px rgba(255, 214, 51, 0.50), 0 0 40px rgba(255, 214, 51, 0.18);
}
body.cursor-right .side--left {
  opacity: 0.10 !important;
  scale: 0.95;
  pointer-events: none;
}


/* ── SIDE ARROW ANIMATION ─────────────────────────────────── */
.side-arrow {
  display: inline-block;
}

body.cursor-left .side--left .side-arrow,
body.cursor-right .side--right .side-arrow {
  animation: arrowDrip 1.1s ease-in-out infinite;
}

@keyframes arrowDrip {
  0%   { transform: translateY(-4px); opacity: 0.25; }
  45%  { transform: translateY(3px);  opacity: 1;    }
  55%  { transform: translateY(3px);  opacity: 1;    }
  100% { transform: translateY(-4px); opacity: 0.25; }
}

/* ── ATTENTION PULSE — brief glow/blink shortly after the page loads,
   to catch the eye that PROJECTS/ARTWORKS are clickable. Plays a few
   times then stops for good (not a permanent distraction). Reuses each
   side's own hover-glow color so it reads as a preview, not a random cue. */
.side--left .side-text {
  animation: sideAttnLeft 1.5s ease-in-out 3.2s 3;
}
.side--right .side-text {
  animation: sideAttnRight 1.5s ease-in-out 3.2s 3;
}

@keyframes sideAttnLeft {
  0%, 100% { opacity: 1;    text-shadow: none; }
  50%      { opacity: 0.68; text-shadow: 0 0 14px rgba(185, 28, 28, 0.42), 0 0 30px rgba(185, 28, 28, 0.16); color: #b91c1c; }
}

@keyframes sideAttnRight {
  0%, 100% { opacity: 1;    text-shadow: none; }
  50%      { opacity: 0.68; text-shadow: 0 0 14px rgba(255, 214, 51, 0.55), 0 0 30px rgba(255, 214, 51, 0.20); color: #ffd633; }
}

/* ================================================================
   PAGE TV OVERLAY — CRT/grain effect on all pages
   All layers: position:fixed, pointer-events:none, z-index 500
   (above page content, well below nav at 9000)
   ================================================================ */

.page-tv-overlay {
  position: fixed;
  inset: 0;
  z-index: 9920;  /* above txOverlay (9900) — grain/vignette visible during transitions */
  pointer-events: none;
  overflow: hidden;
}

/* Horizontal scan lines */
.page-scanlines {
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    transparent              0px,
    transparent              3px,
    rgba(0, 0, 0, 0.07)      3px,
    rgba(0, 0, 0, 0.07)      4px
  );
  pointer-events: none;
}

/* Grain canvas */
.page-grain-canvas {
  display: none !important;
}

/* CRT vignette — darker corners */
.page-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    ellipse at center,
    transparent 52%,
    rgba(0, 0, 0, 0.42) 100%
  );
}

/* Sweeping bright scanner lines */
.page-scanner-lines {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.page-scanner-lines span {
  position: absolute;
  left: 0;
  right: 0;
  top: -4px;
  height: 3px;
  background: rgba(255, 255, 255, var(--op, 0.28));
  mix-blend-mode: multiply;
  box-shadow:
    0  5px 0  rgba(255, 255, 255, 0.12),
    0  9px 0  rgba(255, 255, 255, 0.06),
    0  0  10px rgba(255, 255, 255, 0.12);
  will-change: transform;
  animation: pageScanDown var(--dur, 10s) linear infinite;
  animation-delay: var(--del, 0s);
}
/* Periodic sweep: sweeps in first 62%, hidden remaining 38% */
@keyframes pageScanDown {
  0%   { transform: translateY(0);                   opacity: 0;   }
  3%   { opacity: 1;                                              }
  59%  { transform: translateY(calc(100vh + 8px));   opacity: 0.7; }
  62%  { transform: translateY(calc(100vh + 8px));   opacity: 0;   }
  100% { transform: translateY(calc(100vh + 8px));   opacity: 0;   }
}

/* Subtle edge glow — CRT glass feel */
.page-inner-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(255, 255, 255, 0.04) 0%, transparent 15%),
    linear-gradient(to top,    rgba(255, 255, 255, 0.03) 0%, transparent 12%),
    linear-gradient(to right,  rgba(255, 255, 255, 0.03) 0%, transparent 12%),
    linear-gradient(to left,   rgba(255, 255, 255, 0.03) 0%, transparent 12%);
}

/* Mobile keeps the static CRT framing, scanline texture and vignette, but
   removes every continuously moving texture layer. The fluid canvas is also
   hidden as a CSS fallback in case an older cached script created it first. */
@media (max-width: 768px) {
  .fluid-canvas,
  .page-grain-canvas,
  .page-scanner-lines {
    display: none !important;
  }
}

/* ================================================================
   CRT GLASS BEVEL — inward emboss on the barrel window rim
   Simulates curved CRT glass: top/left bright highlights (light source),
   bottom/right subtle shadow (glass curves away from viewer).
   JS applies the INNER barrel clip-path (non-evenodd) so the bevel
   gradient is visible only inside the screen window, fading to centre.
   z-index: 9945 — just below the dark bezel frame (9950)
   ================================================================ */

.page-crt-bevel {
  position: fixed;
  inset: 0;
  z-index: 10001;
  pointer-events: none;
  /* Single inset shadow — JS barrel clip-path shapes it to the CRT oval.
     Shadow radiates inward from viewport edges; clip cuts to barrel window,
     so darkness follows the curved CRT rim with no corner overlap. */
  box-shadow:
    inset 0 0 70px rgba(0, 0, 0, 0.90),
    inset 0 0 28px rgba(0, 0, 0, 0.68);
}

/* ================================================================
   CRT BEZEL FRAME — real TV screen border on every page
   JS applies evenodd barrel clip-path: dark outside, transparent inside.
   z-index: 9950 → above nav/menus, below cursor (9999)
   ================================================================ */

.page-tv-frame {
  position: fixed;
  inset: 0;
  z-index: 10000;
  pointer-events: none;
  /* Flat pitch black bezel — no gradient, no sheen */
  background: #000000;
  /* Bleed the black 60px past the viewport. The background alone stops at
     the element box, so the edge-softening blur would fade the bezel out
     against the screen border — the OUTER edge would go soft along with
     the inner one. A spread-only shadow paints solid black either side of
     that boundary, so the blur has nothing to fade into there and only the
     inner cut softens. The per-page clip-path script widens the path's
     outer rect to -60 to match; both must move together. */
  box-shadow: 0 0 0 60px #000000;
  /* Start hidden — clip-path JS runs synchronously and sets it visible immediately after */
  visibility: hidden;
}

/* ================================================================
   TV BIOS SCREEN — cyan terminal ID-CARD, appears after 100% load
   Lives inside .tv-screen so CRT overlays (scanlines, grain) apply
   ================================================================ */

.tv-bios {
  /* Amber phosphor — matched to the loading screen that precedes it, so the
     boot sequence reads as one continuous tube rather than changing tube
     colour halfway through. */
  --bx-fg:     #c6a274;   /* base amber text       */
  --bx-bright: #ffe6bd;   /* bright amber          */
  --bx-dim:    rgba(198, 162, 116, 0.30);
  --bx-line:   rgba(198, 162, 116, 0.42);
  --bx-glow:   rgba(255, 176, 80, 0.45);
  position: absolute;
  inset: 0;
  z-index: 2;
  background: #0e0b08;
  padding: clamp(24px, 4vh, 54px) clamp(20px, 4vw, 60px);
  font-family: 'VT323', monospace;
  overflow: hidden;
  opacity: 0;
  clip-path: inset(50% 0);
  transition: clip-path 0.16s ease-out, opacity 0.06s ease;
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.tv-bios.is-visible {
  clip-path: inset(0% 0);
  opacity: 1;
}

/* ── The identity card ─────────────────────────────────────────── */
.bios-card {
  width: 100%;
  max-width: 640px;
  max-height: min(90vh, 760px);
  display: flex;
  flex-direction: column;
  padding: clamp(14px, 2vw, 22px);
  background: rgba(28, 20, 12, 0.55);
  border: 1px solid var(--bx-line);
  box-shadow: 0 0 0 1px rgba(198, 162, 116, 0.10) inset, 0 0 46px rgba(86, 52, 16, 0.38);
}

/* Header bar */
.bios-cardhead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: clamp(10px, 1.6vw, 16px);
  border-bottom: 1px solid var(--bx-line);
}
.bios-chead-id {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: clamp(18px, 2.4vw, 30px);
  color: var(--bx-bright);
  letter-spacing: 0.04em;
}
.bios-chead-sig {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: clamp(13px, 1.7vw, 20px);
  color: var(--bx-fg);
  letter-spacing: 0.14em;
}
.bios-batt {
  display: inline-flex;
  gap: 2px;
  align-items: center;
  padding: 2px;
  border: 1px solid var(--bx-fg);
}
.bios-batt b {
  width: 5px;
  height: 12px;
  background: var(--bx-fg);
  display: block;
}
.bios-batt b:last-child { opacity: 0.25; }   /* "low" — last cell dim */

/* Emblem — small wing/tick glyph used in header + footer */
.bios-emblem {
  width: 26px;
  height: 14px;
  flex-shrink: 0;
  background:
    linear-gradient(90deg, transparent 44%, var(--bx-fg) 44% 47%, transparent 47%),
    repeating-linear-gradient(90deg, var(--bx-fg) 0 2px, transparent 2px 5px);
  -webkit-mask: repeating-linear-gradient(90deg, #000 0 2px, transparent 2px 5px);
          mask: repeating-linear-gradient(90deg, #000 0 2px, transparent 2px 5px);
  opacity: 0.7;
}

/* ID row: portrait + meta */
.bios-idrow {
  display: flex;
  gap: clamp(16px, 2.4vw, 28px);
  align-items: stretch;
  padding: clamp(14px, 2vw, 22px) 0;
}
.bios-portrait {
  position: relative;
  width: clamp(120px, 20vw, 180px);
  aspect-ratio: 3 / 4;
  flex-shrink: 0;
  overflow: hidden;
  border: 1px solid var(--bx-line);
  background: #180f08;
}
.bios-portrait.is-empty img { display: none; }
.bios-portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Amber duotone. sepia() lands around hue 40; the small negative rotate
     pulls it to gold rather than the 140deg swing that made it cyan. */
  filter: grayscale(1) brightness(1.06) contrast(1.28) sepia(1)
          hue-rotate(-12deg) saturate(2.4);
}
.bios-portrait-scan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: multiply;
  background:
    repeating-linear-gradient(0deg, rgba(0,0,0,0.42) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(0,0,0,0.30) 0 1px, transparent 1px 2px);
}
.bios-idmeta {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 6px;
}
.bios-idmeta-access {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: clamp(13px, 1.7vw, 20px);
  color: var(--bx-fg);
  letter-spacing: 0.1em;
  margin-top: 4px;
}
.bios-idmeta-access-lbl { color: var(--bx-fg); }
.bios-idmeta-access-val { color: var(--bx-bright); letter-spacing: 0.24em; }

/* Terminal body — scrolls internally */
.bios-terminal-body {
  flex: 1;
  overflow: hidden;
  min-height: 0;
  padding: clamp(10px, 1.4vw, 16px) 0 clamp(6px, 1vw, 12px);
}

/* Footer bar */
.bios-cardfoot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding-top: clamp(10px, 1.6vw, 16px);
  border-top: 1px solid var(--bx-line);
  font-size: clamp(11px, 1.4vw, 16px);
  color: var(--bx-fg);
  letter-spacing: 0.12em;
}
.bios-cardfoot-txt { opacity: 0.85; }

/* Base line — all typed types inherit this */
.bios-line {
  display: flex;
  align-items: baseline;
  white-space: pre;
  font-size: clamp(14px, 1.7vw, 20px);
  line-height: 1.42;
  color: var(--bx-fg);
  min-height: 0;
}

.bios-line--header {
  font-size: clamp(13px, 1.6vw, 18px);
  color: var(--bx-fg);
  opacity: 0.85;
  letter-spacing: 0.04em;
  white-space: normal;
  margin-top: 6px;
}

.bios-line--sep {
  color: var(--bx-dim);
  font-size: clamp(13px, 1.6vw, 18px);
  overflow: hidden;
}

.bios-line--section {
  font-size: clamp(14px, 1.8vw, 21px);
  color: var(--bx-bright);
  margin-top: 4px;
  letter-spacing: 0.04em;
}

.bios-line--empty {
  font-size: clamp(6px, 0.7vw, 9px);
  line-height: 1;
}

/* Big logo inside the meta column */
.bios-line--logo {
  font-size: clamp(26px, 3.6vw, 46px) !important;
  color: var(--bx-bright) !important;
  letter-spacing: 0.16em;
  line-height: 1.05;
  white-space: nowrap;
  display: block;
  text-shadow: 0 0 22px var(--bx-glow);
}
.bios-line--logo-tag {
  font-size: clamp(12px, 1.5vw, 18px) !important;
  color: var(--bx-fg) !important;
  opacity: 0.8;
  letter-spacing: 0.05em;
  line-height: 1.2;
  white-space: normal;
  display: block;
}

.bl-label { color: var(--bx-fg); }
.bl-ok {
  color: var(--bx-bright);
  text-shadow: 0 0 9px var(--bx-glow);
}

/* Final big lines */
.bios-line--access {
  font-size: clamp(17px, 2.2vw, 28px);
  color: var(--bx-bright);
  letter-spacing: 0.05em;
  margin-top: 3px;
  text-shadow: 0 0 18px var(--bx-glow);
}
.bios-line--welcome {
  font-size: clamp(15px, 1.9vw, 24px);
  color: var(--bx-bright);
  letter-spacing: 0.04em;
}
.bios-line--enter {
  font-size: clamp(13px, 1.6vw, 20px);
  color: var(--bx-fg);
  margin-top: 2px;
  letter-spacing: 0.03em;
}
.bios-line--enter.is-blinking {
  animation: biosStartBlink 0.42s step-end infinite;
}

.bios-cursor {
  display: inline-block;
  width: 0.55em;
  height: 1em;
  background: var(--bx-fg);
  vertical-align: middle;
  margin-left: 2px;
  animation: biosCursorBlink 0.5s step-end infinite;
}

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

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

/* Card responsive */
@media (max-width: 600px) {
  .bios-idrow { gap: 14px; }
  .bios-portrait { width: clamp(96px, 30vw, 130px); }
  .bios-chead-id { font-size: clamp(15px, 5vw, 22px); }
  .bios-cardfoot-txt { font-size: 11px; }
}

/* ================================================================
   CRT INNER STROKE — thin line tracing the barrel window edge
   SVG path element populated by inline script + tv-overlay.js
   z-index: 9951 — just above page-tv-frame (9950)
   ================================================================ */

.page-tv-stroke {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 10002;
  pointer-events: none;
  overflow: visible;
}

@media (max-width: 600px) {
  .tv-bios { padding: clamp(40px, 8vw, 56px) clamp(16px, 4vw, 24px) clamp(40px, 8vw, 56px); }
  .bios-line          { font-size: clamp(12px, 3.6vw, 17px); }
  .bios-line--header  { font-size: clamp(14px, 4.2vw, 20px); }
  .bios-line--section { font-size: clamp(13px, 3.8vw, 18px); }
  .bios-line--access  { font-size: clamp(17px, 5.2vw, 26px); }
  .bios-line--welcome { font-size: clamp(15px, 4.6vw, 22px); }
  .bios-line--enter   { font-size: clamp(13px, 4vw, 18px); }
}

/* ================================================================
   CRT TITLE CARD LOADER — first loading page
   Scoped to .tv-inner--vhs; timing/JS untouched.

   Replaces the old blue tape-deck OSD with a dark showreel-style
   title card: a warm near-black tube with the title glowing amber
   through the glass. The tape-deck chrome is kept but dimmed right
   back so it reads as faint CRT overlay rather than competing with
   the title.
   ================================================================ */
.tv-inner--vhs {
  background:
    /* warm bloom pooling behind the title, as on a lit phosphor tube */
    radial-gradient(120% 78% at 50% 46%, rgba(255, 138, 30, 0.16) 0%, transparent 62%),
    #0e0b08;
}

/* Horizontal tape-noise streaks drifting down the screen */
.tv-inner--vhs::before {
  content: '';
  position: absolute;
  inset: -30px 0;
  z-index: 1;
  pointer-events: none;
  /* far softer than the blue build — on a dark tube the old white
     streaks at 0.55 read as damage rather than texture */
  opacity: 0.22;
  background:
    repeating-linear-gradient(to bottom, rgba(255, 224, 184, 0.07) 0 1px, transparent 1px 6px),
    repeating-linear-gradient(to bottom, transparent 0 92px, rgba(255, 214, 160, 0.14) 92px 94px, transparent 94px 213px);
  animation: vhsStreak 0.9s steps(6) infinite;
}
@keyframes vhsStreak {
  0%   { transform: translateY(0); }
  100% { transform: translateY(26px); }
}

/* OSD text chrome */
.vhs-osd {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: clamp(18px, 4.5vw, 60px) clamp(20px, 5vw, 76px);
  font-family: 'VT323', monospace;
  /* dim amber, not white — subordinate to the title */
  color: rgba(255, 206, 148, 0.34);
  font-size: clamp(15px, 2vw, 27px);
  letter-spacing: 0.14em;
  text-shadow: 0 0 8px rgba(255, 160, 60, 0.28);
  pointer-events: none;
}
.vhs-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
}
.vhs-cell { display: flex; flex-direction: column; gap: 3px; }
.vhs-cell--c { text-align: center; }
.vhs-cell--r { text-align: right; }
.vhs-bottomgroup { display: flex; flex-direction: column; gap: clamp(8px, 1.4vw, 18px); }
.vhs-row--mid {
  opacity: 0.8;
  font-size: clamp(13px, 1.6vw, 21px);
}
.vhs-blink { animation: vhsBlink 1.1s steps(1) infinite; }
@keyframes vhsBlink { 50% { opacity: 0.15; } }
.vhs-track i {
  display: inline-block;
  width: 0.45em;
  height: 0.75em;
  background: rgba(255, 206, 148, 0.42);
  margin-left: 3px;
}
.vhs-track i.off { opacity: 0.25; }

/* Center block: no black panel — the title sits straight on the tube.
   Widened past the shared .tv-panel clamp so a long title like
   PORTFOLIO can run at display size without wrapping. */
.tv-inner--vhs .tv-center { z-index: 6; }
.tv-inner--vhs .tv-panel {
  background: transparent;
  width: min(88vw, 900px);
}

/* Title lockup — small script line stacked over the big glowing word */
.tv-inner--vhs .tv-msg {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(2px, 0.6vh, 10px);
  text-shadow: none;
}

.tv-msg-eyebrow {
  font-family: 'Playfair Display', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  /* the shared .tv-msg rule uppercases everything; this line is
     deliberately lowercase */
  text-transform: none;
  font-size: clamp(0.85rem, 1.9vw, 1.6rem);
  letter-spacing: 0.03em;
  color: #f6e8d2;
  text-shadow: 0 0 12px rgba(255, 190, 120, 0.45);
}

.tv-msg-main {
  font-family: 'Playfair Display', Georgia, serif;
  font-weight: 700;
  font-size: clamp(2.6rem, 9vw, 7.5rem);
  letter-spacing: 0.05em;
  line-height: 1;
  color: #ffd28a;
  /* Layered bloom: near-white core, then amber falling off to a wide
     ember halo — the tube glow from the reference. */
  text-shadow:
    0 0 2px  rgba(255, 245, 220, 0.95),
    0 0 10px rgba(255, 178, 78,  0.95),
    0 0 26px rgba(255, 140, 32,  0.75),
    0 0 55px rgba(255, 112, 16,  0.50),
    0 0 95px rgba(255,  92,  6,  0.28);
}

.tv-inner--vhs .tv-progress::before { border-color: rgba(255, 190, 120, 0.45); }
.tv-inner--vhs .tv-progress-fill {
  /* read by main.js when it paints the segment gradient */
  --tv-seg-color: rgba(255, 197, 122, 0.95);
  box-shadow: 0 0 12px rgba(255, 160, 60, 0.55);
}
.tv-inner--vhs .tv-skip-desktop,
.tv-inner--vhs .tv-skip-mobile { color: #f6e0c2; opacity: 0.6; }

@media (max-width: 600px) {
  .vhs-osd { letter-spacing: 0.08em; }
  .vhs-row--mid { display: none; }
  /* the shared .tv-msg mobile clamp doesn't reach these children */
  .tv-msg-main { font-size: clamp(2.1rem, 12vw, 3.6rem); }
  .tv-msg-eyebrow { font-size: clamp(0.75rem, 3.6vw, 1.05rem); }
}

/* TV BORDER — RE-ENABLED (2026-07-27, on request)

   The original pitch-black bezel is back on every page:
     .page-tv-frame   the black bezel itself (#000, no gradient)
     .page-crt-bevel  the inset shadow curving the screen rim
     .page-tv-stroke  the thin inner stroke line
   The disable block that used to sit here has been removed. Their
   original rules and the per-page clip-path script were never
   touched, so nothing had to be rebuilt. */

/* ── FRAME EDGE SOFTENING ─────────────────────────────────────────
   A light Gaussian blur so the bezel melts into the page instead of
   ending on a hard cut.

   Applied to all three frame layers together: softening only the black
   would leave the bevel's shadow and the inner stroke redrawing a crisp
   line in exactly the same place.

   Only the INNER cut softens. The bezel's black is bled 60px past the
   viewport (see the box-shadow on .page-tv-frame), so at the screen
   border the blur samples solid black either side and the outer edge
   stays crisp — otherwise the bezel faded out against the screen edge
   and looked thin.

   With the outer edge held, the blur can run wider than it safely could
   before: 9px gives roughly a 27px falloff into the page. Tune via
   --tv-edge-blur. */
.page-tv-frame,
.page-crt-bevel,
.page-tv-stroke {
  filter: blur(var(--tv-edge-blur, 9px));
}

/* The home page's boot loader carries its own TV shell — an 8px bezel with a
   grey bevel around a rounded screen. It showed during boot and vanished after,
   which is the border that appeared to "come and go". Flatten it so the boot
   sequence fills the viewport with no bezel. */
.tv-outer {
  padding: 0 !important;
  filter: none !important;
  /* main.js sets an inline barrel clip-path to bow the screen into a CRT
     shape — !important is what defeats that inline style. */
  clip-path: none !important;
}
.tv-outer::before { display: none !important; }
.tv-screen {
  border-radius: 0 !important;
}

/* ================================================================
   HOME BACKGROUND — PLAIN WHITE (2026-07-27, on request)

   The gold contour-line field that used to animate across #bgCanvas
   is switched off in main.js (BG_CONTOURS = false). These two rules
   finish the job: the base goes to pure white, and the noise tile is
   dropped — at opacity 0.5 it was what greyed #FBFBFB down and gave
   the background its linen texture.

   Scoped to the home page only. The global --bg token is untouched,
   so every other page keeps its #FBFBFB base.

   NOTE: static scanlines and vignette remain. The animated page-grain
   canvas is disabled globally because its stretched low-resolution noise
   read as moving pixels over the artwork rather than as CRT texture.
   ================================================================ */
body.page-index {
  background: #ffffff;
}

body.page-index .bg-noise {
  display: none;
}

/* ================================================================
   PAGE TRANSITION — LOADING BAR (2026-08-09)

   Replaces the pixel-waveform that used to fill the transition panels.
   Deliberately the same language as the home boot screen: VT323, a
   segmented block bar and a percentage, so moving between pages reads
   as the same machine loading rather than a separate effect.

   --tx-ink is set per transition by transition.js from the destination
   panel colour's luminance, so this stays legible on the cream, yellow,
   red and black panels alike.
   ================================================================ */
.tx-load {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(14px, 2vh, 22px);
  color: var(--tx-ink, #ffe6bd);
  user-select: none;
}

.tx-load-label {
  font-family: 'VT323', monospace;
  font-size: clamp(1.7rem, 4.4vw, 3rem);
  line-height: 1;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  padding-left: 0.22em;      /* optical centring against the tracking */
  white-space: nowrap;
  max-width: 92vw;
}

/* The 4.4vw term bottoms out at the 1.7rem floor well before the
   viewport gets phone-narrow, and at that floor a longer destination
   name — "AI ADVERTISEMENTS" measured 386px at 375px wide — ran past
   the screen edge with nowrap and nothing to shrink it further, so it
   was silently cropped rather than wrapping or scaling down. Below
   480px the label gets its own, lower floor and is allowed to wrap
   rather than run off-screen; break-word is the backstop for any name
   longer than today's are. */
@media (max-width: 480px) {
  .tx-load-label {
    font-size: clamp(1.15rem, 6.4vw, 1.7rem);
    letter-spacing: 0.14em;
    white-space: normal;
    text-align: center;
    overflow-wrap: break-word;
  }
}

/* Bar: a hairline frame with an 8px gap, exactly like .tv-progress on
   the boot screen. */
.tx-load-bar {
  position: relative;
  width: clamp(190px, 26vw, 380px);
  height: 26px;
  overflow: hidden;
}
.tx-load-bar::before {
  content: '';
  position: absolute;
  inset: -9px;
  border: 1px solid currentColor;
  opacity: 0.5;
  pointer-events: none;
}

/* Segmented fill — blocks with gaps, not a smooth bar. Width is driven
   from JS. */
.tx-load-fill {
  height: 100%;
  width: 0%;
  background: repeating-linear-gradient(
    to right,
    currentColor 0 10px,
    transparent 10px 14px);
}

/* Unused: the numeric read-out was dropped to match the boot screen,
   which hides its own (.tv-pct { display: none }). Kept for reference. */
.tx-load-pct {
  display: none;
  font-family: 'Type Machine', 'Space Grotesk', monospace;
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  opacity: 0.62;
}

@media (prefers-reduced-motion: reduce) {
  /* the bar still fills — it is the progress read-out, not decoration */
  .tx-load-label { letter-spacing: 0.16em; }
}
