/* ============================================================================
   1337ds.com — style.css
   Brand tokens + layout + components. Ported 1:1 from v4 (SILVER ORBIT — BRAND
   PASS). Changes vs v4: orrery rules removed; #heroCanvas added; hero/reveal
   load-in handed to GSAP (initial hidden states here, motion in main.js).
   Brand tokens are SACRED — do not change any hex value.
   ============================================================================ */

:root {
  --volt: #DDEE00; --blue: #1366FF; --cyan: #00D3FF; --violet: #9B5CFF;
  --space-900: #0B0E12; --space-800: #14181E;
  --graphite-600: #5B6470; --graphite-400: #7D858E;
  --silver-400: #C6CBD0; --silver-200: #E2E6E9; --white: #F6F8FA;
  --disp: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'Menlo', monospace;
  --r-sm: 4px; --r-md: 8px;
  --pad: clamp(76px, 10vw, 120px);
  --line: rgba(11, 14, 18, .12);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--sans); color: var(--space-800); font-size: 16px; line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  background:
    radial-gradient(1100px 520px at 85% -5%, rgba(19,102,255,.07), transparent 60%),
    radial-gradient(900px 480px at -10% 30%, rgba(198,203,208,.5), transparent 55%),
    linear-gradient(165deg, var(--white) 0%, var(--silver-200) 48%, #D7DCE0 100%);
  background-attachment: fixed;
}
::selection { background: var(--volt); color: var(--space-900); }
/* v98e a11y: <main> exists ONLY to carry the main landmark (axe landmark-one-main).
   It must generate no box: the seamless deck makes #sheetIntro … #proof and <footer>
   position:sticky against <body>, and a real <main> box would become their containing
   block and end before <footer> — the last sheets would unstick early and the stack
   would break. display:contents keeps the layout bit-for-bit identical. */
main { display: contents; }
h1, h2, h3 { font-family: var(--disp); color: var(--space-900); }
.wrap { max-width: 1750px; margin: 0 auto; padding: 0 clamp(20px, 4vw, 48px); }
.mono, .tag, .eyebrow, label { font-family: var(--mono); }
.eyebrow { font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--graphite-600); display: flex; align-items: center; gap: 12px; }
.eyebrow::before { content: ''; width: 30px; height: 2px; background: var(--volt); }
section { padding: var(--pad) 0; }
.sec-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; margin-bottom: 60px; flex-wrap: wrap; }
.sec-head h2 { font-size: clamp(34px, 4.6vw, 56px); font-weight: 800; letter-spacing: -0.02em; line-height: 1.02; text-transform: uppercase; margin-top: 12px; }
.sec-head h2 em { font-style: normal; color: var(--blue); }

/* ── Custom cursor ── */
@media (pointer: fine) {
  body.cur-on, body.cur-on a, body.cur-on button, body.cur-on select, body.cur-on input, body.cur-on textarea, body.cur-on summary { cursor: none; }
  #cursor { position: fixed; z-index: 9999; width: 7px; height: 7px; border-radius: 50%; background: var(--volt);
    box-shadow: 0 0 8px var(--volt), 0 0 18px rgba(221,238,0,.55); pointer-events: none; transform: translate(-50%,-50%);
    transition: width .18s, height .18s, background .18s; }
  #cursorRing { position: fixed; z-index: 9998; width: 32px; height: 32px; border-radius: 50%;
    border: 1px solid rgba(19,102,255,.65); box-shadow: 0 0 10px rgba(0,211,255,.25); pointer-events: none;
    transform: translate(-50%,-50%); transition: width .22s, height .22s, border-color .22s, opacity .22s; }
  body.cur-hover #cursor { width: 11px; height: 11px; background: var(--cyan); box-shadow: 0 0 10px var(--cyan), 0 0 22px rgba(0,211,255,.6); }
  body.cur-hover #cursorRing { width: 52px; height: 52px; border-color: var(--volt); }
}
@media (pointer: coarse) { #cursor, #cursorRing { display: none; } }

/* ── Scroll reveal (GSAP-driven; initial hidden state here) ── */
[data-rv] { opacity: 0; }
[data-rv].is-in { opacity: 1; }
[data-hero-line] { opacity: 0; }

/* ── Buttons ── */
.btn { display: inline-flex; align-items: center; gap: 10px; font-family: var(--mono); font-size: 12px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; text-decoration: none; padding: 15px 26px; border-radius: var(--r-sm); transition: transform .18s, box-shadow .18s, background .18s, border-color .18s, color .18s; cursor: pointer; }
.btn-volt { background: var(--volt); color: var(--space-900); border: 1px solid var(--volt); }
.btn-volt:hover { transform: translateY(-2px); box-shadow: 0 10px 28px rgba(221,238,0,.4), 0 0 0 1px var(--volt); }
.btn-ghost { background: transparent; color: var(--space-900); border: 1px solid var(--graphite-600); }
.btn-ghost:hover { border-color: var(--blue); color: var(--blue); transform: translateY(-2px); }
.btn .arr { transition: transform .18s; }
.btn:hover .arr { transform: translateX(4px); }

/* ── Nav ── */
nav { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(246,248,250,.82); backdrop-filter: blur(16px); border-bottom: 1px solid var(--line); }
.nav-in { display: flex; align-items: center; justify-content: space-between; height: 68px; max-width: 1750px; }
.nav-links { display: flex; align-items: center; gap: 34px; list-style: none; }
.nav-links a:not(.btn) { font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--graphite-600); text-decoration: none; position: relative; padding-bottom: 4px; }
.nav-links a:not(.btn)::after { content: ''; position: absolute; left: 0; bottom: 0; height: 2px; width: 0; background: var(--volt); transition: width .22s; box-shadow: 0 0 6px rgba(221,238,0,.6); }
.nav-links a:not(.btn):hover { color: var(--space-900); }
.nav-links a:not(.btn):hover::after { width: 100%; }
.nav-cta { padding: 11px 20px !important; font-size: 11.5px !important; }
.logo { display: flex; align-items: center; text-decoration: none; }
.logo svg .ghost { transition: transform .25s; }
.logo:hover svg .ghost { transform: translate(2px, -2px); }

/* ── Hero ── */
#hero { position: relative; min-height: auto; display: flex; flex-direction: column; justify-content: center; overflow: hidden; padding: calc(68px + 7vh) 0 7vh; }   /* v9.15: content-sized hero — EQUAL 7vh empty above/below content (nav=68px fixed); replaces 96vh + translateY raise, so header→hero→services spacing is balanced + tight */
#hero::before { content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image: repeating-linear-gradient(0deg, transparent 0 79px, rgba(11,14,18,.035) 79px 80px), repeating-linear-gradient(90deg, transparent 0 79px, rgba(11,14,18,.035) 79px 80px);
  mask-image: radial-gradient(900px 700px at 70% 45%, #000 30%, transparent 75%); -webkit-mask-image: radial-gradient(900px 700px at 70% 45%, #000 30%, transparent 75%); }
.hero-grid { display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr); gap: 16px; align-items: center; padding-top: 0; position: relative; z-index: 2; }   /* v9.15: header clearance moved to #hero padding (was 96px) */
.hero-meta { font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em; color: var(--graphite-600); text-transform: uppercase; display: flex; align-items: center; gap: 12px; margin-bottom: 30px; }
.hero-meta::before { content: ''; width: 30px; height: 2px; background: var(--volt); box-shadow: 0 0 8px rgba(221,238,0,.7); }
.hero-copy h1 { font-size: clamp(54px, 8vw, 118px); font-weight: 900; line-height: .95; letter-spacing: -0.025em; text-transform: uppercase; }
.hero-copy h1 span { display: block; }
.l1 { background: linear-gradient(100deg, var(--space-900) 0%, var(--space-900) 38%, #3E4A58 50%, var(--space-900) 62%, var(--space-900) 100%);
  background-size: 220% 100%; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: sheen 5.2s ease-in-out infinite; }
@keyframes sheen { 0%, 100% { background-position: 110% 0; } 50% { background-position: -10% 0; } }
.l2 { background: linear-gradient(95deg, var(--blue) 0%, var(--cyan) 30%, #AEB4BA 62%, var(--blue) 100%);
  background-size: 280% 100%; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: flow 6s linear infinite, neonPulse 2.6s ease-in-out infinite; }
@keyframes flow { to { background-position: -280% 0; } }
@keyframes neonPulse {
  0%, 100% { filter: drop-shadow(0 0 6px rgba(0,211,255,.5)) drop-shadow(0 0 18px rgba(19,102,255,.3)); }
  50% { filter: drop-shadow(0 0 14px rgba(0,211,255,.85)) drop-shadow(0 0 34px rgba(150,160,172,.6)); }
}
.l3 { color: transparent; -webkit-text-stroke: 2px var(--graphite-400); animation: strokeGlow 3.4s ease-in-out infinite; }
@keyframes strokeGlow {
  0%, 100% { filter: drop-shadow(0 0 4px rgba(221,238,0,.0)); -webkit-text-stroke-color: var(--graphite-400); }
  50% { filter: drop-shadow(0 0 16px rgba(221,238,0,.55)); -webkit-text-stroke-color: #9aa86b; }
}
.hero-sub { margin-top: 28px; font-size: clamp(20px, 2.1vw, 25px); color: var(--space-800); max-width: 54ch; }
.hero-sub strong { color: var(--space-900); }
.hero-ctas { display: flex; gap: 14px; margin-top: 34px; flex-wrap: wrap; }
.hwrap { display: block; }

/* ── Hero 3D canvas (parametric wave surface — replaces v4 orrery) ── */
.hero-canvas-wrap { position: relative; aspect-ratio: 1; max-height: 80vh; margin-left: auto; width: min(100%, 627px); }
#heroCanvas { display: block; width: 100%; height: 100%; }

/* ── Title block strip ── */
.titleblock { position: relative; z-index: 2; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); margin-top: clamp(36px, 5vw, 60px); background: rgba(246,248,250,.65); backdrop-filter: blur(8px); }
.titleblock .wrap { display: grid; grid-template-columns: repeat(4, 1fr); }
.tb-cell { padding: 18px 22px 16px; border-left: 1px solid var(--line); }
.tb-cell:first-child { border-left: none; padding-left: 0; }
.tb-k { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--graphite-400); margin-bottom: 4px; }
.tb-v { font-family: var(--mono); font-size: 13.5px; font-weight: 600; color: var(--space-900); letter-spacing: .02em; }
.tb-v b { color: var(--blue); font-weight: 600; }

/* ── Capability marquee (GSAP-driven loop) ── */
.capstrip { border-bottom: 1px solid var(--line); padding: 15px 0; overflow: hidden; background: rgba(226,230,233,.5); }
.cap-track { display: flex; width: max-content; will-change: transform; }
.cap-track span { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--graphite-600); white-space: nowrap; }
.cap-track span:not(.sep) {
  background: linear-gradient(95deg, var(--volt) 0%, var(--blue) 48%, var(--volt) 100%);
  background-size: 220% 100%; -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: capFlow 5s linear infinite;
}
@keyframes capFlow { to { background-position: -220% 0; } }
.cap-track .sep { color: var(--volt); padding: 0 22px; text-shadow: 0 0 7px rgba(226,244,0,.5); animation: sepFade 4.5s ease-in-out infinite; }
@keyframes sepFade {
  0%, 100% { color: var(--volt); text-shadow: 0 0 7px rgba(226,244,0,.55); }
  50%      { color: var(--blue); text-shadow: 0 0 7px rgba(19,102,255,.55); }
}

/* ── Intro ── */
#intro .wrap { display: grid; grid-template-columns: 230px 1fr; gap: 52px; }
/* v98m (Κώστας): «κόψε το φωτιστικό, κέντραρε καλύτερα το κείμενο». With the
   graphic gone (ANIM.introGraphic.enabled:false) the two-column grid would leave
   a 230px hole on the left, so the copy collapses to one centred measure. The
   grid rule above stays for the rollback path. */
#intro .intro-side { display: none; }
#intro .wrap { grid-template-columns: 1fr; justify-items: center; }
#intro .intro-body { max-width: 74ch; text-align: center; margin-inline: auto; }
.intro-side { min-height: 300px; } /* v9.10: sideLines out — hosts the Task Lamp graphic (initIntroGraphic) */
.intro-side svg { display: block; overflow: visible; }
.intro-body p { font-size: clamp(20px, 2.3vw, 27px); line-height: 1.45; color: var(--space-800); font-family: var(--disp); font-weight: 600; letter-spacing: -0.01em; }
.intro-body strong { color: var(--space-900); font-weight: 800; }
.intro-body .receipt { font-family: var(--mono); font-size: 12.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--graphite-600); margin-top: 28px; display: flex; align-items: center; gap: 12px; }
.intro-body .receipt::before { content: ''; width: 30px; height: 2px; background: var(--volt); }

/* ── Services ── */
.lead-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-bottom: 18px; }
.sup-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.svc { background: rgba(246,248,250,.78); border: 1px solid var(--line); border-radius: var(--r-md); padding: 32px 28px 28px; position: relative; overflow: hidden; transition: transform .22s, box-shadow .22s, border-color .22s; }
.svc::before { content: ''; position: absolute; top: 0; left: 0; width: 0; height: 3px; background: linear-gradient(90deg, var(--volt), var(--cyan)); transition: width .32s cubic-bezier(.2,.7,.2,1); }
.svc:hover { transform: translateY(-4px); border-color: var(--silver-400); box-shadow: 0 18px 40px rgba(11,14,18,.1); }
.svc:hover::before { width: 100%; }
.svc-lead { background: linear-gradient(180deg, rgba(19,102,255,.05), rgba(246,248,250,.78) 38%); border-top: 2px solid var(--blue); padding-top: 34px; }
.svc-lead .lead-tag { position: absolute; top: 14px; right: 16px; font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em; color: var(--blue); border: 1px solid rgba(19,102,255,.35); border-radius: 3px; padding: 3px 7px; text-transform: uppercase; }
.svc .num { font-family: var(--mono); font-size: 11px; color: var(--graphite-400); letter-spacing: .12em; }
.svc h3 { font-size: 19.5px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 10px; }
.svc p { font-size: 14.5px; color: var(--graphite-600); line-height: 1.66; }
.tagrow { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 18px; }
.tag { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--graphite-600); border: 1px solid var(--line); padding: 5px 10px; border-radius: var(--r-sm); transition: border-color .2s, color .2s; }
.svc:hover .tag { border-color: var(--silver-400); }
.ic { margin: 22px 0 18px; width: 38px; height: 38px; }
.ic svg { width: 38px; height: 38px; stroke-linecap: round; stroke-linejoin: round; }
/* v98j — 3D render icon slot on the service cards (webp, assets/icons-v98j).
   Size is the ONLY thing that changes vs .ic: the render needs ~96px to read.
   --s = per-icon optical-weight factor from site-data.json (imgScale). */
/* v98o — Η ΘΗΚΗ ΚΛΕΙΝΕΙ ΓΥΡΩ ΑΠΟ ΤΟ ΜΕΓΑΛΥΤΕΡΟ ICON. Μετρημένο: το `--s` φτάνει μέχρι
   **1.40** (icon 01), οπότε με θήκη 96 το render έβγαινε **134px** — ξεχείλιζε 38px, δηλαδή
   ξεκινούσε 19px ΠΑΝΩ από τη θήκη, ενώ ο τίτλος κάθε κάρτας είναι στο ΙΔΙΟ top. Αυτό ήταν
   το «δεν είναι έτοιμα»: ίδιος τίτλος, διαφορετικός αέρας από πάνω.
   ⚠ ΔΕΝ αλλάζει το μέγεθος ΚΑΝΕΝΟΣ icon: το `img` κρατάει το ΠΑΛΙΟ base (96px) και το
   `--s` πολλαπλασιάζει πάνω σε αυτό — μόνο το ΚΟΥΤΙ μεγαλώνει σε 134 (= 96 × 1.40) και τα
   κεντράρει όλα. Ο χάρτης imgScale ΔΕΝ πειράζεται: μέτρησα την alpha-weighted οπτική μάζα
   και το εύρος της είναι μόλις **1,27×** (έναντι 1,65× του πλαισίου) — ο χάρτης ΚΑΝΕΙ σωστά
   τη δουλειά του (λεπτό στυλό θέλει μεγαλύτερο κουτί για ίδιο βάρος). Τα margins κόπηκαν
   18/14 → 10/8 ώστε η κάρτα να μη μεγαλώσει όσο η θήκη. */
.ic3d { width: 134px; height: 134px; margin: 10px 0 8px; display: flex; align-items: center; justify-content: center; }
.ic3d img { width: 96px; height: 96px; object-fit: contain; display: block;
  transform: scale(var(--s, 1)); transform-origin: 50% 55%;
  filter: drop-shadow(0 6px 12px rgba(11,14,18,.14));
  transition: transform .3s cubic-bezier(.2,.7,.2,1); }
.svc:hover .ic3d img { transform: translateY(-3px) scale(calc(var(--s, 1) * 1.06)); }
.ic .base { stroke: var(--space-900); fill: none; stroke-width: 1.5; }
.ic .tech { stroke: var(--blue); fill: none; stroke-width: 1.5; }
.ic .hit  { stroke: var(--volt); fill: none; stroke-width: 2; filter: drop-shadow(0 0 3px rgba(221,238,0,.7)); }
.ic .fillv { fill: var(--volt); stroke: none; filter: drop-shadow(0 0 4px rgba(221,238,0,.8)); }
.ic .draw { stroke-dasharray: 70; stroke-dashoffset: 0; }
.svc:hover .ic .draw { animation: dash 1.1s cubic-bezier(.4,0,.2,1) forwards; }
@keyframes dash { from { stroke-dashoffset: 70; } to { stroke-dashoffset: 0; } }
.ic .spin360 { transform-origin: center; transform-box: fill-box; }
.svc:hover .ic .spin360 { animation: icSpin 2.6s linear infinite; }
@keyframes icSpin { to { transform: rotate(360deg); } }
.ic .pulse { transform-origin: center; transform-box: fill-box; }
.svc:hover .ic .pulse { animation: icPulse 1.4s ease-in-out infinite; }
@keyframes icPulse { 0%,100% { transform: scale(1); opacity: 1 } 50% { transform: scale(1.2); opacity: .7 } }
.svc:hover .ic .slide { animation: icSlide 1.6s ease-in-out infinite; }
@keyframes icSlide { 0%,100% { transform: translateX(0) } 50% { transform: translateX(5px) } }
.svc-note { margin-top: 30px; font-size: 14px; color: var(--graphite-600); max-width: 70ch; }

/* ── About ── */
#about { background: linear-gradient(180deg, var(--space-900) 0%, var(--space-800) 100%); position: relative; overflow: hidden; }
#about::after { content: ''; position: absolute; right: -180px; top: -180px; width: 560px; height: 560px; border: 1px dashed rgba(125,133,142,.25); border-radius: 50%; pointer-events: none; }
#about::before { content: ''; position: absolute; right: -80px; top: -80px; width: 360px; height: 360px; border: 1px solid rgba(19,102,255,.2); border-radius: 50%; pointer-events: none; }
#about .wrap { display: grid; grid-template-columns: 1.1fr .9fr; gap: 64px; align-items: start; position: relative; z-index: 2; }
#about .eyebrow { color: var(--graphite-400); }
#about h2 { color: var(--white); font-size: clamp(36px, 5vw, 62px); font-weight: 800; letter-spacing: -0.02em; line-height: 1.0; text-transform: uppercase; margin: 16px 0 28px; }
#about h2 em { font-style: normal; color: var(--volt); text-shadow: 0 0 18px rgba(221,238,0,.35); }
#about p { color: var(--silver-400); font-size: 16.5px; max-width: 56ch; }
#about p strong { color: var(--white); font-weight: 600; }
#about .btn-volt { margin-top: 32px; }
.cred { border: 1px solid rgba(198,203,208,.22); border-radius: var(--r-md); padding: 28px; background: rgba(20,24,30,.6); }
.cred-line { font-family: var(--mono); font-size: 12.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--white); line-height: 1.95; }
.cred-line b { color: var(--volt); font-weight: 600; }
.cred details { margin-top: 18px; }
.cred summary { font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--graphite-400); cursor: pointer; }
.cred summary:hover { color: var(--cyan); }
.cred table { width: 100%; border-collapse: collapse; margin-top: 12px; }
.cred td { font-family: var(--mono); font-size: 11.5px; color: var(--graphite-400); padding: 7px 0; border-top: 1px solid rgba(198,203,208,.12); letter-spacing: .03em; }
.cred td:last-child { text-align: right; color: var(--silver-200); }
.caps-rows { margin-top: 44px; border-top: 1px solid rgba(198,203,208,.18); grid-column: 1 / -1; }
.caps-row { display: grid; grid-template-columns: 1fr auto; gap: 20px; padding: 15px 0; border-bottom: 1px solid rgba(198,203,208,.1); align-items: baseline; transition: padding-left .25s; }
.caps-row:hover { padding-left: 10px; }
.caps-row .c { color: var(--silver-200); font-size: 15.5px; font-weight: 500; }
.caps-row .r { font-family: var(--mono); font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--graphite-400); }
.caps-row:hover .r { color: var(--cyan); }

/* ── Work ── */
.work-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.wk { border: 1px solid var(--line); border-radius: var(--r-md); background: rgba(246,248,250,.8); overflow: hidden; transition: transform .22s, box-shadow .22s; }
.wk:hover { transform: translateY(-4px); box-shadow: 0 18px 40px rgba(11,14,18,.12); }
.wk-img { aspect-ratio: 16/10; background: linear-gradient(150deg, var(--silver-200), var(--silver-400)); border-bottom: 1px solid var(--line); display: flex; align-items: center; justify-content: center; position: relative; overflow: hidden; }
.wk-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* v98o — ΤΑ ΣΚΙΤΣΑ ΕΞΩ ΑΠΟ ΤΟ WORK (αίτημα Κώστα 31/7: «δεν θέλω τα sketched icons/products»).
   Το 3D shelf ΠΟΤΕ δεν είχε σκίτσο — η καμβά-υφή του (makeTexCanvas) είναι gradient +
   blueprint grid + ghost index + «RENDER SLOT». Κρύβοντας το svg, το static grid γίνεται
   ΤΑΥΤΟ με το shelf, που ήταν εξαρχής η πρόθεση («ίδια εικόνα desktop shelf ↔ grid ↔ mobile»).
   Kill switch: σβήσε το `display:none` — τα line-art placeholders επιστρέφουν αυτούσια
   (το `iconSVG(w.placeholderId)` και το site-data.json ΔΕΝ πειράχτηκαν). */
.wk-img svg { display: none; }
.wk-img > svg { transition: transform .35s cubic-bezier(.2,.7,.2,1); }
.wk:hover .wk-img svg { transform: scale(1.06) rotate(-1deg); }
.wk:hover .wk-img img { transform: scale(1.06); }
.slot-label { position: absolute; bottom: 9px; right: 12px; font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--graphite-600); opacity: .8; }
.wk-body { padding: 20px 22px 22px; }
.wk-idx { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--graphite-400); }
.wk-idx b { color: var(--blue); font-weight: 500; }
.wk h3 { font-size: 18px; font-weight: 700; margin: 8px 0 6px; letter-spacing: -0.01em; }
.wk p { font-size: 14px; color: var(--graphite-600); }
.nda-line { margin-top: 32px; font-size: 14.5px; color: var(--graphite-600); display: flex; align-items: center; gap: 12px; }
.nda-line::before { content: ''; width: 30px; height: 2px; background: var(--volt); }

/* ── Process ── */
#process { background: rgba(226,230,233,.45); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.proc { border-top: 1px solid var(--line); }
.proc-row { display: grid; grid-template-columns: 90px 300px 1fr; gap: 28px; padding: 28px 0; border-bottom: 1px solid var(--line); align-items: baseline; transition: background .2s, padding-left .25s; position: relative; }
.proc-row::after { content: ''; position: absolute; left: 0; bottom: -1px; height: 2px; width: var(--ld, 0); background: linear-gradient(90deg, var(--volt), transparent); }
.proc-row:hover { background: rgba(246,248,250,.6); padding-left: 12px; }
.proc-row .n { font-family: var(--mono); font-size: 13px; color: var(--blue); letter-spacing: .06em; }
.proc-row:hover .n { color: var(--volt); text-shadow: 0 0 8px rgba(221,238,0,.6); }
.proc-row h3 { font-size: 18.5px; font-weight: 700; letter-spacing: -0.01em; }
.proc-row p { font-size: 14.5px; color: var(--graphite-600); }
.proc-row.keystep { background: linear-gradient(90deg, rgba(19,102,255,.06), transparent 70%); }

/* ── Contact ── */
#contact .wrap { display: grid; grid-template-columns: 1fr 1.1fr; gap: 64px; }
#contact h2 { font-size: clamp(34px, 4.6vw, 56px); font-weight: 800; line-height: 1.0; letter-spacing: -0.02em; text-transform: uppercase; margin: 16px 0 32px; }
#contact h2 em { font-style: normal; color: var(--blue); }
.c-rows { border-top: 1px solid var(--line); }
.c-row { display: grid; grid-template-columns: 130px 1fr; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--line); font-size: 14.5px; }
.c-row .k { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--graphite-400); padding-top: 2px; }
.c-row a { color: var(--blue); text-decoration: none; border-bottom: 1px solid transparent; transition: border-color .2s, color .2s; }
.c-row a:hover { color: var(--cyan); border-color: var(--cyan); }
.qual-line { margin-top: 24px; font-size: 14px; color: var(--graphite-600); }
form { border: 1px solid var(--line); border-radius: var(--r-md); padding: 30px; background: rgba(246,248,250,.85); }
.f-head { font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--graphite-600); margin-bottom: 22px; display: flex; align-items: center; gap: 12px; }
.f-head::before { content: ''; width: 30px; height: 2px; background: var(--volt); }
.f-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.f-field { display: flex; flex-direction: column; gap: 7px; }
.f-field.full { grid-column: 1 / -1; }

/* v98f — SAME BUG AS THE v98b MOBILE FIX, ONE BAND HIGHER.
   v98b bound the contact form's controls and grid cells with min-width:0, but
   only inside the ≤960px block. Between 961px and ~1100px the two-column
   #contact .wrap is still active, and there the second track still cannot
   shrink below the form's min-content width — 2 × the browser's default input
   width + padding = 606px. 606 + the 64px gap + the left column exceeded the
   viewport and pushed 29px of horizontal scroll at 1024px, 69px at 961px:
   exactly the small-laptop band, and the one band that gets neither the mobile
   layout nor enough room for the desktop one.
   The two rules are the v98b rules verbatim, re-applied where the columns are
   still side by side. They are idempotent — the controls are already
   width:100%, and min-width:0 only removes an automatic floor — and the range
   is closed at 1100px so the ≥1101px desktop layout is untouched, byte for
   byte. No brand token is involved. */
@media (min-width: 961px) and (max-width: 1100px) {
  #briefForm input, #briefForm select, #briefForm textarea {
    width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box; }
  #contact .wrap, #contact .wrap > div, .f-grid, .f-field, .c-rows, .c-row {
    min-width: 0; }
}

label { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--graphite-600); }
input, select, textarea { font-family: var(--sans); font-size: 16px; color: var(--space-900); background: var(--white); border: 1px solid var(--silver-400); border-radius: var(--r-sm); padding: 13px 14px; transition: border-color .2s, box-shadow .2s; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(19,102,255,.18); }
textarea { min-height: 130px; resize: vertical; }
.f-foot { display: flex; align-items: center; justify-content: space-between; gap: 18px; margin-top: 22px; flex-wrap: wrap; }
.proof-chip { font-family: var(--mono); font-size: 11px; letter-spacing: .07em; text-transform: uppercase; color: var(--graphite-600); text-decoration: none; border-bottom: 1px solid var(--silver-400); transition: color .2s, border-color .2s; }
.proof-chip:hover { color: var(--blue); border-color: var(--blue); }
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.f-success { display: none; padding: 14px 16px; border: 1px solid var(--blue); border-radius: var(--r-sm); color: var(--blue); font-size: 14.5px; margin-top: 16px; background: rgba(19,102,255,.06); }

/* ── Footer ── */
footer { background: var(--space-900); color: var(--graphite-400); padding: 44px 0; }
footer .wrap { display: grid; grid-template-columns: auto 1fr auto; gap: 28px; align-items: center; }
footer ul { display: flex; gap: 26px; list-style: none; justify-content: center; }
footer ul a { font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--graphite-400); text-decoration: none; transition: color .2s, text-shadow .2s; }
footer ul a:hover { color: var(--volt); text-shadow: 0 0 10px rgba(221,238,0,.5); }
footer .f-meta { font-family: var(--mono); font-size: 11px; letter-spacing: .06em; text-transform: uppercase; text-align: right; }
/* v98e a11y (color-contrast): `opacity:.5` dropped --graphite-400 (#7D858E) to an
   effective #444A50 on #0B0E12 = 2.15:1 — a WCAG AA fail on 10px text. No token
   changed: the text now renders at the FULL --graphite-400 the rest of the site
   already uses for muted mono labels (.wk-idx, .svc .num, .caps-row .r) = 5.22:1.
   The hairline is halved so the divider keeps exactly the weight it had under .5. */
footer .f-credit { grid-column: 1 / -1; text-align: center; font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--graphite-400); margin-top: 26px; padding-top: 15px; border-top: 1px solid rgba(255,255,255,.03); }
footer .f-credit .cutg { height: 1em; vertical-align: -0.18em; opacity: .85; }

/* ── Responsive ── */
@media (max-width: 1024px) {
  .hero-grid { grid-template-columns: 1fr; gap: 8px; }
  .hero-canvas-wrap { max-height: 46vh; width: min(84vw, 460px); margin: 0 auto; order: -1; }
  .hero-copy h1 { font-size: clamp(48px, 10.5vw, 92px); }
}
@media (max-width: 960px) {
  .titleblock .wrap { grid-template-columns: 1fr 1fr; }
  .tb-cell { border-left: none; padding-left: 0; }
  .lead-grid, .sup-grid, .work-grid { grid-template-columns: 1fr 1fr; }
  #about .wrap, #contact .wrap, #intro .wrap { grid-template-columns: 1fr; }
  .proc-row { grid-template-columns: 64px 1fr; }
  .proc-row p { grid-column: 2; }
}
@media (max-width: 640px) {
  .lead-grid, .sup-grid, .work-grid, .f-grid { grid-template-columns: 1fr; }
  .nav-links li:not(:last-child) { display: none; }
}

/* ── Reduced motion ──
   Intentionally minimal. The hero wave + reveals are the whole point of this
   page and now run regardless of the OS "reduce motion" setting — Windows
   "animation effects: off" was previously disabling the entire experience.
   Only page smooth-scroll is relaxed here. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ═══════════ Revision 2 — studio voice / proof / process band / hero balance ═══════════ */

/* Hero: copy wider and pushed left */
#hero .hero-grid { grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.7fr); gap: 24px; max-width: 1750px; width: 100%; }
.hero-sub { max-width: 60ch; }

/* Animated process band (between marquee and intro) */
#process-flow { padding: clamp(30px, 5vw, 58px) 0; border-bottom: 1px solid var(--line); background: rgba(246,248,250,.4); }
.pf-eyebrow { margin-bottom: 28px; }
.pf-track { position: relative; display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.pf-line { position: absolute; left: 0; right: 0; top: 13px; height: 2px; background-image: repeating-linear-gradient(90deg, var(--silver-400) 0 6px, transparent 6px 12px); }
.pf-line-fill { position: absolute; inset: 0; width: 100%; transform: scaleX(1); transform-origin: left center; background: linear-gradient(90deg, var(--volt), var(--cyan)); box-shadow: 0 0 8px rgba(221,238,0,.4); }
.pf-node { position: relative; z-index: 1; flex: 1; display: flex; flex-direction: column; align-items: center; gap: 12px; text-align: center; }
.pf-dot { width: 28px; height: 28px; display: grid; place-items: center; font-family: var(--mono); font-size: 11px; font-weight: 700; color: var(--space-900); background: var(--white); border: 1px solid var(--graphite-600); border-radius: var(--r-sm); box-shadow: 0 0 0 5px rgba(246,248,250,.85); transition: border-color .2s, color .2s, box-shadow .2s, transform .2s; }
.pf-node:hover .pf-dot { border-color: var(--blue); color: var(--blue); transform: translateY(-2px); box-shadow: 0 0 0 5px rgba(246,248,250,.85), 0 6px 16px rgba(19,102,255,.18); }
.pf-label { font-family: var(--mono); font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--graphite-600); max-width: 15ch; line-height: 1.4; }
@media (max-width: 640px) {
  .pf-track { flex-direction: column; align-items: flex-start; gap: 20px; }
  .pf-line { left: 13px; right: auto; top: 4px; bottom: 4px; width: 2px; height: auto; background-image: repeating-linear-gradient(180deg, var(--silver-400) 0 6px, transparent 6px 12px); }
  .pf-line-fill { transform-origin: top center; background: linear-gradient(180deg, var(--volt), var(--cyan)); }
  .pf-node { flex-direction: row; gap: 14px; text-align: left; }
  .pf-label { max-width: none; }
}

/* About: single column after cred moved to proof */
#about .wrap { grid-template-columns: 1fr; }
#about .caps-rows { margin-top: 38px; }

/* Proof section (final credibility band, light bg) */
#proof { border-top: 1px solid var(--line); }
.proof-head { margin-bottom: 40px; }
.proof-head h2 { font-size: clamp(34px, 4.6vw, 56px); font-weight: 800; letter-spacing: -0.02em; line-height: 1.02; text-transform: uppercase; margin-top: 12px; }
.proof-head h2 em { font-style: normal; color: var(--blue); }
.proof-stats { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: rgba(246,248,250,.5); }
.proof-body { display: grid; grid-template-columns: 1.1fr .9fr; gap: 48px; align-items: center; margin-top: 44px; }
/* v98s — ΔΟΜΙΚΟ ΦΡΑΓΜΑ. Το `min-width:auto` (default σε grid item) αφήνει ένα παιδί να
   ξεπεράσει την κολόνα του όσο θέλει· εδώ το `.cert-badges` φούσκωσε το `.cred` σε 602px
   μέσα σε κολόνα 354px και το `#proof{overflow-x:clip}` το έκοβε σιωπηλά. Το `min-width:0`
   κάνει την κολόνα ΔΕΣΜΕΥΤΙΚΗ: ό,τι κι αν μπει μέσα, δεν βγαίνει έξω από την κάρτα.
   Το κρατάμε ΚΑΙ μετά τη διόρθωση των badges — είναι το δίχτυ για το επόμενο παιδί. */
.proof-body > * { min-width: 0; }
/* cred block re-themed for light bg */
#proof .cred { background: rgba(246,248,250,.72); border-color: var(--line); }
#proof .cred-line { color: var(--space-900); }
#proof .cred-line b { color: var(--blue); }
#proof .cred summary { color: var(--graphite-600); }
#proof .cred summary:hover { color: var(--blue); }
#proof .cred td { color: var(--graphite-600); border-top-color: var(--line); }
#proof .cred td:last-child { color: var(--space-900); }

/* CSWE badge — floating, with sheen */
.proof-badge { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 16px; }
/* v98e: `overflow:hidden` was only inside the ≤960px block, so on desktop the
   ::after sheen (translateX, `alternate`) swept ~78px past the badge and gave
   the DOCUMENT a horizontal scrollbar. Invisible while the seamless deck owns
   the scroll, very visible on the no-3D fallback — which is now a path real
   (GPU-less) desktops take. The sheen is meant to travel across the badge, so
   clipping it to the badge box is the intent, not a workaround. */
.badge-wrap { position: relative; width: clamp(160px, 22vw, 232px); aspect-ratio: 1; overflow: hidden; }
/* v98m rev4 (Κώστας): «βγάλε το γκρι background shadow — όταν κουνιέται εμφανίζεται
   και δεν είναι ωραίο». Το drop-shadow ζωγράφιζε τη ΣΚΙΑ ΤΟΥ ΤΕΤΡΑΓΩΝΟΥ badge· με το
   badgeFloat να το γέρνει σε 3D, η σκιά ξεπρόβαλλε από τη μια πλευρά σαν γκρι πλακάκι.
   Με το κομμένο badge (χωρίς το λευκό πλαίσιο) δεν έχει πια πάνω τι να πέσει. */
#cswiBadge { width: 100%; height: 100%; object-fit: contain; display: block; animation: badgeFloat 7s ease-in-out infinite; }
@keyframes badgeFloat {
  0%, 100% { transform: perspective(900px) rotateY(-10deg) rotateX(4deg) translateY(0); }
  50%      { transform: perspective(900px) rotateY(10deg)  rotateX(-3deg) translateY(-8px); }
}
/* v98m rev4: το sheen ήταν ΟΡΘΟΓΩΝΙΟ όσο όλο το κουτί και σάρωνε με `screen`. Όσο το
   badge γέμιζε το κουτί (λευκό πλαίσιο) περνούσε ΠΑΝΩ του· τώρα που το badge είναι
   κομμένο, το ορθογώνιο σάρωνε ΚΕΝΟ φόντο κι έδειχνε σαν γκρι πλάκα να περνάει.
   Kill switch: ξανα-ενεργοποίησέ το αν επιστρέψει το badge με πλαίσιο. */
.badge-wrap::after { content: none; }
@keyframes badgeSheen { 0%, 33% { transform: translateX(-130%); } 67%, 100% { transform: translateX(130%); } }
.badge-cap { font-family: var(--mono); font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--graphite-600); }
.badge-wrap.badge-missing { display: grid; place-items: center; border: 1px dashed var(--silver-400); border-radius: var(--r-md); }
.badge-wrap.badge-missing::before { content: attr(data-fallback); font-family: var(--mono); font-weight: 700; font-size: 30px; letter-spacing: .08em; color: var(--blue); }
.badge-wrap.badge-missing::after { display: none; }

@media (max-width: 960px) {
  #hero .hero-grid { grid-template-columns: 1fr; }
  .proof-body { grid-template-columns: 1fr; gap: 34px; }
  .proof-stats { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  .proof-stats { grid-template-columns: 1fr; }
}

/* ═══════════ PLANETARY SERVICES — pinned 3D system (planetary.js) ═══════════ */
#planetary { padding: 0; position: relative; }
.pl-stage { position: relative; height: 100vh; overflow: hidden; }
#planetaryCanvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.pl-copy { position: absolute; top: 104px; left: 50%; transform: translateX(-50%); width: 100%; max-width: 1750px; padding: 0 clamp(20px, 4vw, 48px); box-sizing: border-box; z-index: 2; pointer-events: none; }
.pl-copy h2 { font-size: clamp(30px, 4vw, 50px); font-weight: 800; letter-spacing: -0.02em; line-height: 1.02; text-transform: uppercase; margin-top: 12px; }
.pl-copy h2 em { font-style: normal; color: var(--blue); }
.pl-hint { position: absolute; bottom: 4vh; left: 50%; transform: translateX(-50%); z-index: 2; font-family: var(--mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase; color: var(--graphite-600); white-space: nowrap; pointer-events: none; }
#plHintB { opacity: 0; }
/* v98j: το label διαβάζεται πλέον πάνω από ΟΤΙΔΗΠΟΤΕ — chip από χαρτί + hairline,
   λίγο μεγαλύτερο type. Τοποθετείται ακτινικά έξω από το icon (planetary.js). */
.pl-label { position: fixed; left: 0; top: 0; opacity: 0; pointer-events: none; white-space: nowrap; font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--space-900); will-change: transform; background: rgba(246,248,250,.88); border: 1px solid rgba(11,14,18,.10); border-radius: 3px; padding: 3px 8px; box-shadow: 0 2px 6px rgba(11,14,18,.07); }
.pl-label .lab-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 6px; vertical-align: middle; border: 1px solid rgba(11,14,18,.35); }
.pl-label.is-lead { font-size: 12px; font-weight: 600; border-color: rgba(19,102,255,.28); }
#plOverlay { position: fixed; inset: 0; z-index: 6; pointer-events: none; visibility: hidden; }
#plCard { position: fixed; left: 0; top: 0; width: 320px; z-index: 7; opacity: 0; visibility: hidden; padding: 26px 24px 22px; box-shadow: 0 18px 50px rgba(11,14,18,.16); will-change: transform; }
#plCard .c-accent { position: absolute; top: 0; left: 0; width: 100%; height: 3px; background: var(--volt); }
#plCard .ic { margin: 16px 0 12px; }
#planetary:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
@media (max-width: 640px) {
  #plCard { width: min(86vw, 320px); }
  .pl-copy h2 { font-size: 28px; }
}

/* ═══════════ v7.1 — services dedup · planetary text · process band ═══════════ */

/* The planetary system IS the services presentation. The grid stays in the DOM
   as the SEO/no-WebGL fallback and hides only when the 3D actually runs
   (planetary.js adds html.pl-on on successful init). */
html.pl-on #services { display: none; }
.about-note { margin-top: 26px; font-size: 13.5px; color: var(--graphite-400) !important; max-width: 70ch; }

/* Planetary text upgrade — bigger, fuller, readable over the canvas */
.pl-sub { margin-top: 14px; font-size: 15.5px; line-height: 1.55; color: var(--graphite-600); max-width: 46ch; }
.pl-sub strong { color: var(--space-900); }
.pl-label { font-size: 12px; letter-spacing: .14em; background: none; border: 0; padding: 0; border-radius: 0; backdrop-filter: none; box-shadow: none; text-shadow: 0 0 4px rgba(246,248,250,.95), 0 1px 2px rgba(246,248,250,.85); }
.pl-label.is-lead { font-size: 13px; }
.pl-hint { font-size: 12.5px; letter-spacing: .2em; color: var(--space-800); background: none; padding: 0; border: 0; border-radius: 0; backdrop-filter: none; text-shadow: 0 0 4px rgba(246,248,250,.95); }
#plCard { width: 340px; }
#plCard h3 { font-size: 20.5px; }
#plCard p { font-size: 15px; line-height: 1.6; }

/* Process band — engineered path 01→05, stations light as the line passes */
.pf-line { background-image: none; }
.pf-svg { position: absolute; left: 0; right: 0; top: -3px; width: 100%; height: 8px; overflow: visible; display: block; }
.pf-rail { stroke: var(--silver-400); stroke-width: 2; stroke-dasharray: 0.9 1.4; fill: none; }
.pf-draw { stroke: url(#pfGrad); stroke-width: 2.5; fill: none; filter: drop-shadow(0 0 6px rgba(226,244,0,.4)); }
.pf-node .pf-dot { width: 40px; height: 40px; font-size: 12.5px; opacity: .45; transition: opacity .25s, background .25s, color .25s, border-color .25s, transform .4s cubic-bezier(.34,1.56,.64,1), box-shadow .3s; }
.pf-node .pf-label { opacity: .45; font-size: 11.5px; transition: opacity .25s, color .25s; }
.pf-node.pf-active .pf-dot { opacity: 1; background: var(--volt); border-color: var(--space-900); transform: translateY(-3px); box-shadow: 0 0 0 5px rgba(246,248,250,.85), 0 10px 22px rgba(226,244,0,.35); }
.pf-node.pf-active .pf-label { opacity: 1; color: var(--space-900); font-weight: 600; }
@media (max-width: 640px) {
  .pf-svg { display: none; }
  .pf-line { background-image: repeating-linear-gradient(180deg, var(--silver-400) 0 6px, transparent 6px 12px); }
  .pf-node .pf-dot, .pf-node .pf-label { opacity: 1; }
}

/* ═══════════ v7.2 — hero Section Cut: HUD microcopy + second sub line ═══════════ */
.hero-sub .hs2 { display: block; margin-top: 12px; font-size: .92em; color: var(--graphite-600); }
.hero-sub .hs2 strong { color: var(--space-900); }
.hero-hud { position: absolute; z-index: 3; font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--graphite-400); line-height: 1.9; pointer-events: none; }
.hero-hud b { color: var(--blue); font-weight: 600; }
.hero-hud.hud-tl { top: 6px; left: 2px; text-align: left; }
.hero-hud.hud-tr { top: 6px; right: 2px; text-align: right; color: var(--blue); }
@media (max-width: 1024px) { .hero-hud { display: none; } }

/* ═══════════ v7.3 — hero rebalance: calmer headline, room for the body ═══════════ */
#hero .hero-grid { grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr); gap: 20px; }
.hero-copy h1 { font-size: clamp(42px, 6vw, 86px); }
.hero-copy { max-width: 560px; }
/* glossiness downtune: sheen slower, neon pulse removed, stroke glow off */
.l1 { animation-duration: 8.5s; }
.l2 { animation: flow 9s linear infinite; }
.l3 { animation: none; filter: none; -webkit-text-stroke-color: var(--graphite-400); }
@media (max-width: 1024px) { .hero-copy { max-width: none; } .hero-copy h1 { font-size: clamp(42px, 9.5vw, 80px); } }

/* ═══════════ v7.4 — process band: glyph chips + hover zoom + desc panel ═══════════ */
.pf-node { cursor: pointer; outline: none; transition: transform .32s cubic-bezier(.34,1.56,.64,1); }
.pf-chip { width: 56px; height: 56px; display: grid; place-items: center; background: var(--white);
  border: 1px solid var(--graphite-600); border-radius: 6px;
  box-shadow: 0 0 0 5px rgba(246,248,250,.85); opacity: .5;
  transition: opacity .25s, border-color .25s, box-shadow .3s, background .25s; }
.pf-chip svg { width: 32px; height: 32px; stroke-linecap: round; stroke-linejoin: round; }
/* v98m — 3D icon variant. The rendered object IS the chip, so the white card,
   border and ring come off: a machined part sitting on the sheet reads as an
   object, the same way the planetary bodies do. Box grows 56→76 (see the rail
   offset below, which follows it). No background = nothing to clash with the
   icon's own contact shadow. */
.pf-chip3d { width: 88px; height: 88px; background: none; border: 0; border-radius: 0;
  box-shadow: none; overflow: visible; }
.pf-chip3d img { width: 88px; height: 88px; display: block; object-fit: contain;
  transition: transform .35s cubic-bezier(.2,.7,.2,1), filter .3s; }
.pf-chip .base { stroke: var(--space-900); fill: none; stroke-width: 1.5; }
.pf-chip .tech { stroke: var(--blue); fill: none; stroke-width: 1.5; }
.pf-chip .hit { stroke: var(--volt); fill: none; stroke-width: 2; filter: drop-shadow(0 0 3px rgba(226,244,0,.7)); }
.pf-chip .fillv { fill: var(--volt); stroke: none; filter: drop-shadow(0 0 4px rgba(226,244,0,.8)); }
.pf-chip .draw { stroke-dasharray: 70; stroke-dashoffset: 0; }
.pf-num { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; color: var(--graphite-400); }
.pf-svg { top: 24px; }
.pf-node.pf-active .pf-chip { opacity: 1; }
.pf-node.pf-active .pf-label { opacity: 1; color: var(--space-900); font-weight: 600; }
.pf-node:hover, .pf-node:focus-visible, .pf-node.pf-open { transform: translateY(-6px) scale(1.14); }
.pf-node:hover .pf-chip, .pf-node:focus-visible .pf-chip, .pf-node.pf-open .pf-chip {
  opacity: 1; border-color: var(--space-900); background: var(--volt);
  box-shadow: 0 0 0 5px rgba(246,248,250,.85), 0 14px 28px rgba(226,244,0,.35); }
.pf-node:hover .pf-chip .tech, .pf-node.pf-open .pf-chip .tech { stroke: var(--space-900); }
.pf-node:hover .pf-label, .pf-node.pf-open .pf-label { color: var(--space-900); opacity: 1; }
.pf-node:hover .pf-chip .draw, .pf-node.pf-open .pf-chip .draw { animation: dash 1.1s cubic-bezier(.4,0,.2,1) forwards; }
.pf-node:hover .pf-chip .pulse, .pf-node.pf-open .pf-chip .pulse { animation: icPulse 1.4s ease-in-out infinite; transform-origin: center; transform-box: fill-box; }
.pf-node:hover .pf-chip .slide, .pf-node.pf-open .pf-chip .slide { animation: icSlide 1.6s ease-in-out infinite; }
/* v98m — the 3D chip overrides the volt-fill hover of the SVG variant: painting
   a volt background behind a rendered object kills it. The object itself does
   the reacting — it lifts and drops a real shadow. Rail rides 10px lower to stay
   on the centreline of the taller box (76 vs 56). */
/* v98m rev2 (Κώστας): the parts render FULLY at rest — no dimming, nothing to
   "wake up". The SVG chips could sit at .45 because line art reads fine faded;
   a photoreal render at .45 just looks out of focus. It also failed silently on
   the static path, where .pf-active never fires and they stayed dim forever.
   Rest = 100%. Hover = the part grows and lifts. */
.pf-node .pf-chip3d { opacity: 1; transition: transform .4s cubic-bezier(.34,1.56,.64,1); }
.pf-node.pf-active .pf-chip3d { opacity: 1; }
.pf-node:hover .pf-chip3d, .pf-node:focus-visible .pf-chip3d, .pf-node.pf-open .pf-chip3d {
  opacity: 1; background: none; border: 0; box-shadow: none; }
.pf-node:hover .pf-chip3d img, .pf-node:focus-visible .pf-chip3d img, .pf-node.pf-open .pf-chip3d img {
  transform: translateY(-7px) scale(1.20);
  filter: drop-shadow(0 14px 20px rgba(11,14,18,.26)); }
/* Labels read at rest too — .45 grey under a full-strength object looked like a
   rendering fault rather than a state. Still a clear step up when active. */
.pf-track.pf-3d .pf-label { opacity: .78; }
.pf-track.pf-3d .pf-num { color: var(--graphite-600); }
.pf-track.pf-3d .pf-node.pf-active .pf-label,
.pf-track.pf-3d .pf-node:hover .pf-label { opacity: 1; }
/* The class comes from buildProcessFlow, not :has() — one less browser-support
   surface, and it is set at the same moment the icons are. 76px box ⇒ centre at
   44px; the rail sits inside .pf-line (top:13px) and draws at y=4 of its own
   box, so 27 + 13 + 4 = 44. */
.pf-track.pf-3d .pf-svg { top: 27px; }
/* The rail runs BEHIND the parts. With flat chips it did not matter (the white
   card hid it); a cut-out object has transparent gaps, so an un-layered rail
   draws straight across the machined body and flattens it. Explicit z-index on
   both sides — the .pf-draw drop-shadow makes its own stacking context, so
   relying on DOM order alone is not safe here. */
.pf-track.pf-3d .pf-line { z-index: 0; }
.pf-track.pf-3d .pf-node { z-index: 2; }
.pf-desc { overflow: hidden; height: 0; opacity: 0; }
.pf-desc-in { padding-top: 26px; display: flex; align-items: baseline; gap: 18px; max-width: 1010px; }
.pf-desc-in .n { font-family: var(--mono); font-size: 13px; color: var(--blue); letter-spacing: .06em; white-space: nowrap; }
.pf-desc-in h3 { font-family: var(--disp); font-size: 19px; font-weight: 700; letter-spacing: -.01em; text-transform: uppercase; color: var(--space-900); white-space: nowrap; }
.pf-desc-in p { font-size: 14.5px; line-height: 1.6; color: var(--graphite-600); }
.pf-desc-in .keytag { display: block; width: fit-content; margin-top: 8px; font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--space-900); background: var(--volt); border: 1px solid var(--space-900); border-radius: 3px; padding: 2px 7px; }
@media (max-width: 640px) {
  .pf-node:hover, .pf-node.pf-open { transform: none; }
  .pf-chip { opacity: 1; }
  .pf-desc-in { flex-direction: column; gap: 8px; }
  .pf-desc-in h3 { white-space: normal; }
}

/* ═══════════ v7.5 — hero layering: the masthead sits OVER the system ═══════════
   Orbiting bodies pass BEHIND the headline (the V6 reference behaves the same).
   One stacking order, no collisions, full-size orbits preserved. */
#hero .hero-copy { position: relative; z-index: 3; }
#hero .hero-canvas-wrap { z-index: 1; }


/* ════ v8 HERO — 3D logo "1337ds" + parametric mesh background ════ */
.mesh-bg { position: fixed; inset: 0; z-index: -1;
  width: 100%; height: 100%; display: block; pointer-events: none; }
#hero { position: relative; }
.hero-scene { position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; display: block; pointer-events: none; }
#hero .hero-grid { position: relative; z-index: 2; }
#hero h1 { font-size: clamp(29px, 3.45vw, 48px); }   /* v8: smaller headline */
@media (max-width: 1024px) { #hero h1 { font-size: clamp(26px, 7.1vw, 42px); } }
.cutg { height: 1.15em; width: auto; display: inline-block;
  vertical-align: -0.22em; margin: 0 1px; }
/* v97q: anchor-scroll offset — sections land below the fixed nav (native / reduced-motion path)
   v98o — 80px → 65px. ΤΟ ΚΕΝΟ ΠΟΥ ΑΝΕΦΕΡΕ Ο ΚΩΣΤΑΣ ΖΕΙ ΕΔΩ, ΟΧΙ ΜΟΝΟ ΣΤΟ JS. Στο static /
   no3d path (κινητά ΚΑΙ κάθε desktop χωρίς GPU — δηλαδή το μηχάνημα του Κώστα) το `initScroll`
   γυρίζει νωρίς χωρίς gsap, οπότε τα nav clicks τα χειρίζεται ο browser με ΑΥΤΟΝ τον αριθμό —
   το `DECK_OFF` του main.js ΔΕΝ αγγίζει ποτέ αυτή τη διαδρομή. Μετρημένο: nav **69px** ≥960 και
   **61px** ≤768 (`.nav-in` 68→60 στο @media 768), άρα το 80 άφηνε λωρίδα του ΠΡΟΗΓΟΥΜΕΝΟΥ
   section **11px** σε desktop και **19px** σε κινητό, σε ΚΑΘΕ anchor — όχι μόνο στο process.
   65 = 69 − 4 ⇒ 4px χώνονται κάτω από τον (ημιδιαφανή + blur) nav· ίδιο tuck με το 3D path,
   ασφαλές και σε non-integer zoom. Το mobile ζευγάρι (57 = 61 − 4) είναι στο @media 768. */
#hero, #planetary, #process-flow, #services, #work, #about, #contact, #proof { scroll-margin-top: 65px; }
/* "meets" — Inked Dimension (triggers στο assembleEnd του logo) */
.mt { font-style: normal; position: relative; display: inline-block;
  background: linear-gradient(90deg, #1366FF 0 50%, #2A323B 50% 100%);
  background-size: 200% 100%; background-position: 100% 0;
  -webkit-background-clip: text; background-clip: text; color: transparent; }
.mt::after { content: ''; position: absolute; left: .02em; right: .04em; bottom: .03em;
  height: 2px; background: var(--volt); transform: scaleX(0); transform-origin: left; }
.ink-on .mt { background-position: 0 0;
  transition: background-position .6s cubic-bezier(.65,0,.35,1) .15s; }
.ink-on .mt::after { transform: scaleX(1);
  transition: transform .45s cubic-bezier(.65,0,.35,1) .07s; }

/* tech-border metrology frame — hero outer-edge overlay (above mesh, below copy) */
#techframe { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; }

/* ════ v9.6 — HERO RAISE (Kostas 2026-06-26): halve the top gap ════
   Vertical move ONLY (no scale → the 3D logo's slot-fit stays intact; scale was
   what collapsed it). Text + logo move up together (logo tracks the slot rect).
   Tune the vh to change how far up. */
#hero .hero-grid { transform: none; }   /* v9.15: v9.6 raise removed — content now centered with equal top/bottom gap via #hero padding */

/* ════ v9.9 — process band: hover spline-arrow segments (2026-07-15) ════
   Hover a station: curved arrows draw through the gaps 01→N in sequence
   (main.js builds the per-gap SVGs; knobs in ANIM.processFlow.segments). */
.pf-seg { position: absolute; height: 44px; overflow: visible; pointer-events: none;
  opacity: 0; visibility: hidden; }
.pf-seg path { fill: none; stroke-linecap: round; }
.pf-chip.pf-flash { opacity: 1; background: var(--volt); border-color: var(--space-900);
  box-shadow: 0 0 0 5px rgba(246,248,250,.85), 0 10px 22px rgba(221,238,0,.5);
  transition: opacity .12s, background .12s, border-color .12s, box-shadow .12s; }

/* v96q road block αφαιρέθηκε (v97d — STUDIO minimal, βλ. τέλος αρχείου) */

/* ── v96r — Igloo Energy 1/4: smooth scroll (lenis) + magnetic ── */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }
.btn { will-change: transform; }


/* ================== v96z — SEAMLESS DECK (Igloo Energy 4/4, variant C) ==================
   Post-planetary sections = stacked sheets: sticky με top:var(--st) (min(0, 100vh−ύψος)
   από initSeamlessDeck στο main.js) + z-ladder· τα ψηλά φύλλα σκρολάρουν ολόκληρα πριν
   καρφώσουν, μετά τα σκεπάζει το επόμενο. ΚΑΘΑΡΑ ΦΥΛΛΑ (απόφαση Κώστα 2026-07-21): το
   mesh-bg σβήνει στην είσοδο του deck (fade trigger #sheetIntro — initScroll). Gate:
   html.deck-on (μπαίνει ΜΟΝΟ όταν ANIM.seamless.enabled && pl-on — fallback χωρίς
   planetary ΔΕΝ παίρνει deck, το #services εμφανίζεται μόνο εκεί). */
html.deck-on #sheetIntro, html.deck-on #work, html.deck-on #about,
html.deck-on #contact, html.deck-on #proof, html.deck-on footer {
  position: sticky; top: var(--st, 0px);
}
html.deck-on #sheetIntro { z-index: 2; background: #EEF1F4;
  /* v98m (Κώστας 2026-07-28, screenshot): όταν το φύλλο process+intro είναι κοντύτερο
     από το viewport, κάρφωνε με --st:0 και το σκούρο WORK γέμιζε το κάτω μέρος της
     οθόνης. Το φύλλο τώρα πιάνει ΠΑΝΤΑ τουλάχιστον όλο το viewport (100svh — ό,τι
     μετράει και το hero, v98i CLS fix) και το περιεχόμενο κεντράρεται κάθετα ώστε
     τα κενά να μοιράζονται πάνω/κάτω αντί να μαζεύονται σε μαύρη λωρίδα.
     Desktop-deck-only gate (html.deck-on) — mobile/static path ΑΘΙΚΤΟ. */
  min-height: 100svh; display: flex; flex-direction: column; justify-content: center; }
html.deck-on #sheetIntro #process-flow, html.deck-on #sheetIntro #intro {
  background: transparent; border-bottom: 0;   /* ΕΝΑ φύλλο — μία επιφάνεια */
}
html.deck-on #work    { z-index: 3; background: #F2F4F6; }
html.deck-on #about   { z-index: 4; }
html.deck-on #contact { z-index: 5; background: #F6F8FA; }
html.deck-on #proof   { z-index: 6; background: #EEF1F4; border-top: 0; }
html.deck-on footer   { z-index: 7; }
/* ════ v98q — READING HOLD (αίτημα Κώστα 31/7: «δεν μπορώ να σταματήσω σε ένα section
   χωρίς να ξεπροβάλλει το επόμενο· πρέπει να είμαι πολύ ακριβής και αργός με τη ρόδα»)

   ΜΕΤΡΗΜΕΝΗ ΑΙΤΙΑ — ΤΟ DECK ΔΕΝ ΕΙΧΕ ΚΑΘΟΛΟΥ «ΑΚΙΝΗΤΟ» ΠΑΡΑΘΥΡΟ. Ένα φύλλο κολλάει στο
   `top: min(0, 100vh − ύψος)`, δηλαδή με τον ΠΑΤΟ του ακριβώς στον πάτο του viewport. Το
   επόμενο φύλλο ξεκινάει αμέσως μετά στη ροή ⇒ τη στιγμή που το τρέχον γεμίζει την οθόνη,
   το επόμενο ΗΔΗ ανεβαίνει. Μετρημένο σε 1512×950, notch = **216px**:
   notch 12 → sheetIntro **98%**  ·  notch 13 → work **14%** ήδη μέσα.
   Το «καθαρό» παράθυρο ήταν **μικρότερο από ΕΝΑ notch**. Δεν ήταν θέμα ταχύτητας —
   ΔΕΝ ΥΠΗΡΧΕ θέση να σταματήσεις. Γι' αυτό το duration 2.4 / multiplier 0.72 του rev3
   δεν το έλυσε: έκαναν το ίδιο μηδενικό παράθυρο πιο αργό, όχι μεγαλύτερο.

   ΛΥΣΗ — δύο πράγματα, κανένα από τα δύο δεν είναι scroll-snap (που παλεύει με το διάβασμα):
   1) `min-height: 100svh` σε ΚΑΘΕ φύλλο. Τα #contact (781px) και #proof (795px) ήταν
      ΚΟΝΤΥΤΕΡΑ από το viewport (950), οπότε ακόμα και καρφωμένα άφηναν λωρίδα του επόμενου
      από κάτω. Ίδια οικογένεια με το v98m fix του #sheetIntro — τώρα καθολικά.
   2) `margin-bottom: var(--hold)` — καθαρός χώρος ΜΕΤΑ το φύλλο. Το φύλλο είναι sticky,
      άρα μένει καρφωμένο και καλύπτει ΟΛΟ το viewport όσο κυλάει αυτό το margin· το επόμενο
      ξεκινάει `--hold` px αργότερα. ⚠ `margin` ΔΕΝ μπαίνει στο `offsetHeight` ⇒ ο υπολογισμός
      `--st` του initSeamlessDeck ΜΕΝΕΙ ΣΩΣΤΟΣ χωρίς καμία αλλαγή σε JS.
   Kill switch: `--hold: 0px` → ακριβώς η προηγούμενη συμπεριφορά. */
:root { --hold: clamp(340px, 52svh, 620px); }   /* ← Ο ΜΟΝΟΣ ΜΟΧΛΟΣ. 0px = παλιά συμπεριφορά. */
/* ⚠ ΤΟ #proof ΕΞΑΙΡΕΙΤΑΙ ΣΚΟΠΙΜΑ (Κώστας 31/7, screenshot: «delete empty grid bottom area»).
   Είναι το ΤΕΛΕΥΤΑΙΟ section πριν το footer — δεν έχει «επόμενο» να κρύψει, οπότε το hold
   εκεί παράγει μόνο νεκρό χώρο. Μετρημένο πριν την εξαίρεση: **768px κενού** κάτω από την
   κάρτα στο static (min-height 1444 vs κάρτα 555· `#proof` έχει background **transparent**,
   άρα φαινόταν το grid της σελίδας) και 275px + 494px margin στο deck.
   ΚΑΝΟΝΑΣ: το `--hold` ισχύει για κάθε section ΕΚΤΟΣ του τελευταίου. */
html.deck-on #sheetIntro, html.deck-on #work, html.deck-on #about,
html.deck-on #contact {
  min-height: 100svh;
  margin-bottom: var(--hold);
}
/* Static / no-3D desktop (καμία deck — το scroll το κάνει ο browser): ίδιος στόχος,
   ΑΛΛΟΣ μηχανισμός. ⚠ ΕΔΩ ΤΟ `margin-bottom` ΕΙΝΑΙ ΛΑΘΟΣ: χωρίς sticky, το margin είναι
   ΠΡΑΓΜΑΤΙΚΟ ΚΕΝΟ — μετρημένο, άφηνε 3 notches με το φόντο της σελίδας ανάμεσα στα sections.
   Σωστό: το ΙΔΙΟ το section γίνεται ψηλότερο από το viewport κατά `--hold` και το περιεχόμενο
   κεντράρεται· έτσι υπάρχουν `--hold` px σκρολ όπου το section γεμίζει ΟΛΗ την οθόνη με το
   ΔΙΚΟ του φόντο. ΔΕΝ αγγίζει touch/mobile — εκεί η ροή είναι σκόπιμα απλή. */
@media (min-width: 961px) and (pointer: fine) {
  html:not(.deck-on) #sheetIntro, html:not(.deck-on) #work, html:not(.deck-on) #about,
  html:not(.deck-on) #contact {                       /* #proof εξαιρείται — βλ. σχόλιο πάνω */
    min-height: calc(100svh + var(--hold));
  }
}
/* ⚠⚠ ΔΥΟ ΜΕΤΡΗΜΕΝΑ ΛΑΘΗ ΠΟΥ ΕΚΑΝΑ ΕΔΩ ΚΑΙ ΤΑ ΕΠΙΑΣΑ — ΜΗΝ ΤΑ ΞΑΝΑΚΑΝΕΙΣ:

   1. `margin-bottom` στο static = ΠΡΑΓΜΑΤΙΚΟ ΚΕΝΟ. Δουλεύει μόνο σε sticky φύλλα (deck),
      όπου το καρφωμένο φύλλο σκεπάζει το margin. Χωρίς sticky άφηνε 3 notches φόντου
      ανάμεσα στα sections. Γι' αυτό εδώ το ύψος μπαίνει ΜΕΣΑ στο section (`+ var(--hold)`).

   2. `display:flex` στα static sections **ΙΣΟΠΕΔΩΣΕ ΤΟ ΠΛΑΤΟΣ**. Το `.wrap` έχει
      `margin-inline:auto`, και σε flex container το auto margin στον cross άξονα
      **ακυρώνει το stretch** ⇒ το item γίνεται fit-content. Μετρημένο στο #proof:
      `.wrap` **1750 → 880**, κάρτα 883 → 405, σειρά badges **104 → 48px**, σε ΟΛΑ τα πλάτη.
      Δεν βγάζει error, δεν πέφτει το PSI — φαίνεται μόνο αν μετρήσεις πλάτη.
      **ΚΑΝΟΝΑΣ: μην αλλάζεις `display` σε section που περιέχει `.wrap` με auto margins.
      Μόνο `min-height`.** (Το `justify-content:center` κόστισε και δεύτερο bug: μετακίνησε
      το `#process-flow` ~300px μέσα στο φύλλο ⇒ nav landing −307px, ακριβώς ο νόμος
      «το seat είναι το ΦΥΛΛΟ, όχι το περιεχόμενο» του v98m rev3.)
   Το επιπλέον ύψος κάθεται στον πάτο κάθε section, με το ΔΙΚΟ του φόντο — αυτό αρκεί:
   ο στόχος είναι «να μη φαίνεται το επόμενο», όχι κάθετο κεντράρισμα. */
html.deck-on #sheetIntro, html.deck-on #work, html.deck-on #about,
html.deck-on #contact, html.deck-on #proof, html.deck-on footer { border-radius: 28px 28px 0 0; }
html.deck-on #sheetIntro, html.deck-on #work, html.deck-on #contact,
html.deck-on #proof { box-shadow: 0 -24px 60px rgba(11,14,18,.22); }
html.deck-on #about, html.deck-on footer { box-shadow: 0 -24px 60px rgba(11,14,18,.35); }
/* volt hairline στην ακμή των σκοτεινών φύλλων — extra bg layer (τα ::before/::after
   του #about είναι πιασμένα από τους διακοσμητικούς κύκλους) */
html.deck-on #about { background:
  linear-gradient(90deg, transparent 4%, rgba(221,238,0,.4) 18%, rgba(221,238,0,.12) 50%, transparent 92%) top / 100% 1px no-repeat,
  linear-gradient(180deg, var(--space-900) 0%, var(--space-800) 100%); }
html.deck-on footer { background:
  linear-gradient(90deg, transparent 4%, rgba(221,238,0,.4) 18%, rgba(221,238,0,.12) 50%, transparent 92%) top / 100% 1px no-repeat,
  var(--space-900); }

/* ---------- v96z — THE STUDIO heading: κάθετο 13⟨τομή⟩37 stack + λέξεις δίπλα ----------
   (pick Κώστα 2026-07-21: όλα τα κείμενα ισομεγέθη — τα ψηφία στο μέγεθος του h2).
   Markup στο site-data.json about.headingHtml (.hstack + .words), class h2-cut στο h2. */
#about h2.h2-cut { display: flex; align-items: center; gap: .42em; }
#about h2.h2-cut .hstack { display: flex; flex-direction: column; align-items: center; line-height: .92; }
#about h2.h2-cut .hstack svg.cutg-h { display: block; width: 1.42ch; height: auto; margin: .1em 0; color: var(--white); }
#about h2.h2-cut .words { line-height: 1.0; }


/* ═══════════════════════════════════════════════════════════════════════════
   v97b — WORK CHAPTER (2026-07-22)
   (1) PROJECT DETAIL SHEET — skeleton, light φύλλο (fallback) + dark override
   (2) BLUEPRINT CAROUSEL (variant D) — DOM fallback, πάντα wired
   (3) «THE SHELF v2 MONUMENT» — WebGL layer, gated σε html.wk3d-on (JS routing)
   Όλα τα accents μπλε — κανένα volt σε motion. Dark sheet: #14181E + --blue-300.
   ═══════════════════════════════════════════════════════════════════════════ */

/* κάρτες WORK: clickable → project sheet */
#workGrid .wk { cursor: pointer; }

/* ---- PROJECT DETAIL SHEET (skeleton — δομή μόνο, placeholders παντού) ---- */
#projSheet { position: fixed; inset: 0; z-index: 8000; background: #F4F6F8;
  border-radius: 28px 28px 0 0; transform: translateY(103%);
  transition: transform .62s cubic-bezier(.72,0,.2,1); overflow-y: auto;
  overscroll-behavior: contain; box-shadow: 0 -30px 80px rgba(11,14,18,.4); }
#projSheet.open { transform: translateY(0); }
html.sheet-lock, html.sheet-lock body { overflow: hidden; }
.ps-top { position: sticky; top: 0; z-index: 5; display: flex; align-items: center;
  justify-content: space-between; gap: 20px; padding: 18px clamp(20px, 4vw, 56px);
  background: rgba(244,246,248,.92); backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); }
.ps-top .ps-meta { font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--graphite-400); }
.ps-top .ps-meta b { color: var(--blue); font-weight: 500; }
.ps-wrap { max-width: 1180px; margin: 0 auto; padding: clamp(28px,4vw,54px) clamp(20px,4vw,56px) 80px; }
.ps-wrap h1 { font-size: clamp(30px, 4.2vw, 54px); font-weight: 800; letter-spacing: -0.02em;
  line-height: 1.02; text-transform: uppercase; margin: 6px 0 26px; }
.ps-hero { aspect-ratio: 21/9; background: linear-gradient(150deg, var(--silver-200), var(--silver-400));
  border: 1px solid var(--line); border-radius: 12px; position: relative; margin-bottom: 34px; }
.ps-slot-label { position: absolute; right: 12px; bottom: 10px; font-family: var(--mono);
  font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--graphite-400); }
.ps-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 34px; }
.ps-tags span { font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--graphite-600); border: 1px solid var(--line);
  border-radius: 999px; padding: 6px 12px; background: rgba(255,255,255,.5); }
.ps-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; margin-bottom: 44px; }
/* v98e a11y: markup moved h3 → h2 (heading-order under #psTitle). Both are kept
   in the selector so the rule survives either markup — same type scale, no visual
   change whatsoever. */
.ps-cols h2, .ps-cols h3 { font-family: var(--mono); font-size: 11.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--blue); margin-bottom: 10px; }
.ps-cols h2::before, .ps-cols h3::before { content: '— '; color: var(--volt-dim, #b7c400); }
.ps-cols p { font-size: 15px; color: var(--graphite-600); }
.ps-gallery { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-bottom: 44px; }
.ps-gallery .ps-g { aspect-ratio: 16/10; background: linear-gradient(150deg, var(--silver-200), var(--silver-400));
  border: 1px solid var(--line); border-radius: 10px; position: relative; }
.ps-cta-row { display: flex; align-items: center; gap: 18px; }
.ps-note { font-family: var(--mono); font-size: 11px; color: var(--graphite-400); }
@media (max-width: 900px) { .ps-cols { grid-template-columns: 1fr; } .ps-gallery { grid-template-columns: 1fr; } }
  

/* D «BLUEPRINT 3D» + CAROUSEL — B's blueprint identity (frame draw, grid,
   corner ticks) + 3D materialize entrance, cursor tilt, horizontal snap track
   with depth falloff. ALL accents blue (#1366FF) — no volt anywhere (client).
   All .bp-*/.bpd-* overlays are injected from JS → a no-JS page never gets
   them and shows the stock grid (initial hides are gsap.set only, never CSS). */
#workGrid .wk { position: relative; }
#workGrid .bp-frame, #workGrid .bp-grid, #workGrid .bp-tick,
#workGrid .bpd-veil, #workGrid .bpd-tag { position: absolute; pointer-events: none; }
/* frame that "draws itself" — blue 1.5px stroke, pathLength-normalized dash */
#workGrid .bp-frame { inset: 0; width: 100%; height: 100%; z-index: 6;
  display: block; overflow: visible; }
#workGrid .bp-frame rect { fill: none; stroke: var(--blue, #1366FF); stroke-width: 1.5; }
/* fine blueprint grid on the render slot — 1px lines every 12px, both axes */
#workGrid .bp-grid { inset: 0; z-index: 2; opacity: .5;
  background:
    repeating-linear-gradient(0deg,  rgba(19,102,255,.10) 0 1px, transparent 1px 12px),
    repeating-linear-gradient(90deg, rgba(19,102,255,.10) 0 1px, transparent 1px 12px); }
/* .bp-done (entrance finished) hands the grid to CSS: idle <-> hover via vars from JS */
#workGrid .wk.bp-done .bp-grid { opacity: var(--bp-grid-idle, .18);
  transition: opacity .25s ease; }
#workGrid .wk.bp-done.bp-hover .bp-grid { opacity: var(--bp-grid-hover, .45); }
/* corner dimension ticks — BLUE L-brackets, 10px, hover only */
#workGrid .bp-tick { width: 11px; height: 11px; z-index: 7; opacity: 0;
  transform: scale(.85); transition: opacity .22s ease, transform .22s ease; }
#workGrid .bp-tick svg { display: block; width: 100%; height: 100%; }
#workGrid .bp-tick.tl { top: 7px;    left: 7px; }
#workGrid .bp-tick.tr { top: 7px;    right: 7px; transform: rotate(90deg)  scale(.85); }
#workGrid .bp-tick.br { bottom: 7px; right: 7px; transform: rotate(180deg) scale(.85); }
#workGrid .bp-tick.bl { bottom: 7px; left: 7px;  transform: rotate(270deg) scale(.85); }
#workGrid .wk.bp-done.bp-hover .bp-tick { opacity: 1; }
#workGrid .wk.bp-done.bp-hover .bp-tick.tl { transform: scale(1); }
#workGrid .wk.bp-done.bp-hover .bp-tick.tr { transform: rotate(90deg)  scale(1); }
#workGrid .wk.bp-done.bp-hover .bp-tick.br { transform: rotate(180deg) scale(1); }
#workGrid .wk.bp-done.bp-hover .bp-tick.bl { transform: rotate(270deg) scale(1); }
/* index line reads blueprint-blue while measuring */
#workGrid .wk .wk-idx { transition: color .22s ease; }
#workGrid .wk.bp-done.bp-hover .wk-idx { color: var(--blue, #1366FF); }

/* ── carousel track (.bpd-on is added by JS — no-JS keeps the stock grid) ── */
#workGrid.bpd-on { display: flex; gap: 18px; overflow-x: auto;
  scroll-snap-type: x mandatory; overscroll-behavior-x: contain;
  scrollbar-width: none; -ms-overflow-style: none;
  perspective: 900px;                    /* one vanishing point: materialize + tilt + depth */
  padding: 30px 0 56px; margin: -30px 0 -56px; }  /* room for lift/shadow/rotation inside the scrollport */
#workGrid.bpd-on::-webkit-scrollbar { display: none; }
#workGrid.bpd-on .wk { flex: 0 0 calc((100% - 36px) / 3); scroll-snap-align: start;
  transition: box-shadow .22s;           /* transform transition OFF — gsap is the only transform writer */
  will-change: transform; }
#workGrid.bpd-on .wk:hover { transform: none; }  /* stock -4px CSS lift folded into the tilt writer */
@media (max-width: 900px) { #workGrid.bpd-on .wk { flex-basis: calc((100% - 18px) / 1.5); } }
/* depth veil — off-center dimming WITHOUT touching the card's own opacity */
#workGrid .bpd-veil { inset: 0; z-index: 8; background: #F1F4F6; opacity: 0; }
/* nav arrows — right-aligned above the track; auto-hidden when everything fits */
#work .wk-nav { display: flex; justify-content: flex-end; gap: 10px; margin-bottom: 14px; }
#work .wk-nav button { width: 40px; height: 40px; border: 1px solid var(--line);
  border-radius: 8px; background: rgba(246,248,250,.7); font-family: var(--mono);
  font-size: 15px; line-height: 1; color: var(--graphite-600, #4A5560); cursor: pointer;
  transition: color .2s ease, border-color .2s ease; }
#work .wk-nav button:hover:not(:disabled) { color: var(--blue, #1366FF);
  border-color: var(--blue, #1366FF); }
#work .wk-nav button:disabled { opacity: .35; cursor: default; }
#work .wk-nav.bpd-hidden { display: none; }

/* ═══ WORK-3D v2 «MONUMENT PASS» (webgl layer — appended after D; everything
   gated on html.wk3d-on, added by JS after mode routing. Without it this whole
   block is inert and variant D above is the live fallback.) ═══ */

/* §1 chapter sheet — dark override of html.deck-on #work (kept from v1) */
html.wk3d-on #work {
  background:
    linear-gradient(90deg, transparent 4%, rgba(19,102,255,.45) 18%,
                    rgba(19,102,255,.12) 50%, transparent 92%) top / 100% 1px no-repeat,
    #0B0E12;
  padding: 0;
  /* v9.17: WORK is a TALL deck sheet. The .wk-stage (100vh, sticky top:0) pins
     while #work scrolls through, so entering WORK gives a ~60vh dwell on the
     pinned 01 station (drag/arrows to browse) instead of blowing straight
     through into #about in a single scroll. Dwell length = min-height - 100vh;
     tune this one value for feel (140vh = shorter hold, 200vh = longer). */
  min-height: 160vh;
}
html.wk3d-on #work > .wrap { display: none; }   /* D UI suppressed — D stays wired (fallback) */
html.wk3d-on #workGrid, html.wk3d-on #work .wk-nav { display: none; }
/* v97d: το scroll-behavior guard αφαιρέθηκε — το rail δεν γράφει πλέον page
   scroll (drag/βέλη/click μόνο), οπότε δεν υπάρχει λόγος να πειράζεται το
   site-wide smooth behavior σε webgl mode. */

html.wk3d-on .wk-stage { position: sticky; top: 0; height: 100vh; overflow: hidden;
  border-radius: 28px 28px 0 0; background: #0B0E12; }
html.wk3d-on .wk3-canvas { position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; touch-action: none; user-select: none; -webkit-user-select: none; }
html.wk3d-on .wk3-canvas.is-ptr { cursor: pointer; }

/* §1 header top-left (reparented sec-head clone — white h2, em blue) */
html.wk3d-on .wk3-head { position: absolute; top: 104px; left: clamp(20px, 4vw, 48px);
  z-index: 4; opacity: 1; pointer-events: none; }
html.wk3d-on .wk3-head .eyebrow { color: #C6CBD0; }
html.wk3d-on .wk3-head .eyebrow::before { background: #1366FF; }   /* no yellow anywhere */
html.wk3d-on .wk3-head h2 { font-size: clamp(34px, 4.6vw, 56px); font-weight: 800;
  letter-spacing: -0.02em; line-height: 1.02; text-transform: uppercase;
  margin-top: 12px; color: #F6F8FA; }
html.wk3d-on .wk3-head h2 em { font-style: normal; color: #1366FF; }

/* §1 NDA bottom-left 44px */
html.wk3d-on .wk3-nda { position: absolute; left: clamp(20px, 4vw, 48px); bottom: 44px;
  max-width: 44ch; z-index: 4; pointer-events: none; }
html.wk3d-on .wk3-nda .nda-line { color: #C6CBD0; margin-top: 0; opacity: 1; transform: none; }
html.wk3d-on .wk3-nda .nda-line::before { background: #1366FF; }

/* §1 DOM type layer — title block bottom-left 128px */
html.wk3d-on .wk3-type { position: absolute; left: clamp(20px, 4vw, 48px); bottom: 128px;
  z-index: 4; pointer-events: none; max-width: 46ch; }
html.wk3d-on .wk3-type .wk3-meta { font-family: var(--mono); font-size: 11.5px;
  letter-spacing: .12em; text-transform: uppercase; color: #7D858E; margin-bottom: 10px; }
html.wk3d-on .wk3-type .wk3-meta b { color: #5C93FF; font-weight: 500; }
html.wk3d-on .wk3-type h3 { font-size: clamp(22px, 2.4vw, 34px); font-weight: 800;
  letter-spacing: -0.01em; line-height: 1.05; text-transform: uppercase; color: #F6F8FA; }

/* §1 bottom-right cluster 44px: 01/07 + 120×2 progress rail + [←][→] 44px */
html.wk3d-on .wk3-corner { position: absolute; right: clamp(20px, 4vw, 48px); bottom: 44px;
  display: flex; align-items: center; gap: 16px; z-index: 5; }
html.wk3d-on .wk3-prog { font-family: var(--mono); font-size: 12px; letter-spacing: .14em;
  color: #C6CBD0; }
html.wk3d-on .wk3-rail { width: 120px; height: 2px; background: rgba(198,203,208,.18);
  position: relative; overflow: hidden; }
html.wk3d-on .wk3-rail i { position: absolute; inset: 0; background: #5C93FF;
  transform-origin: 0 50%; transform: scaleX(0); }
html.wk3d-on .wk3-corner button { width: 44px; height: 44px; border: 1px solid rgba(198,203,208,.22);
  border-radius: 8px; background: transparent; font-family: var(--mono); font-size: 15px;
  line-height: 1; color: #C6CBD0; cursor: pointer; transition: color .2s ease, border-color .2s ease; }
html.wk3d-on .wk3-corner button:hover:not(:disabled) { color: #5C93FF; border-color: #5C93FF; }
html.wk3d-on .wk3-corner button:disabled { opacity: .35; cursor: default; }

/* §1 drag hint */
html.wk3d-on .wk3-hint { position: absolute; left: 50%; bottom: 4vh; transform: translateX(-50%);
  font-family: var(--mono); font-size: 11px; letter-spacing: .18em; color: #7D858E;
  z-index: 4; pointer-events: none; white-space: nowrap; }

/* ═══ §5 PROJECT SHEET — dark variant (class wk3d only while webgl mode open;
   fallback keeps the light skeleton untouched) ═══ */
#projSheet.wk3d { --blue-300: #5C93FF; background: #14181E;
  border-radius: 28px 28px 0 0; box-shadow: 0 -30px 80px rgba(0,0,0,.6);
  transition: transform .7s cubic-bezier(.32,.72,0,1); }   /* §4 retimed open, master ease */
#projSheet.wk3d:not(.open) { transition-duration: .55s; }  /* §4 close 0.55s */
#projSheet.wk3d .ps-top { background: rgba(20,24,30,.9); backdrop-filter: blur(12px);
  border-bottom: 1px solid rgba(198,203,208,.14); }
#projSheet.wk3d .ps-top .ps-meta { color: #7D858E; }
#projSheet.wk3d .ps-top .ps-meta b { color: var(--blue-300); }
#projSheet.wk3d .wk3-idx { color: var(--blue-300); }
#projSheet.wk3d #psBack { border-color: #5B6470; color: #E2E6E9; background: transparent; }
#projSheet.wk3d #psBack:hover { border-color: var(--blue-300); color: var(--blue-300); }
#projSheet.wk3d .ps-wrap { max-width: 1240px; padding-bottom: 120px; }
#projSheet.wk3d .ps-wrap h1 { font-size: clamp(40px, 4.5vw, 88px); font-weight: 800;
  letter-spacing: -0.03em; color: #F6F8FA; margin: 10px 0 36px; }
#projSheet.wk3d .ps-hero { aspect-ratio: 21/9; background: #0B0E12;
  border: 1px solid rgba(198,203,208,.12); border-radius: 16px; margin-bottom: 48px;
  overflow: hidden; }
#projSheet.wk3d .ps-hero .wk3-heroTex { position: absolute; inset: 0; width: 100%;
  height: 100%; display: block; }
#projSheet.wk3d .ps-slot-label { color: #5B6470; }
#projSheet.wk3d .ps-tags span { border-color: rgba(198,203,208,.18); color: #C6CBD0;
  background: rgba(255,255,255,.03); }
#projSheet.wk3d .ps-cols { gap: 40px; margin-bottom: 64px; }
#projSheet.wk3d .ps-cols h2, #projSheet.wk3d .ps-cols h3 { color: var(--blue-300); font-size: 11.5px; letter-spacing: .14em; }
#projSheet.wk3d .ps-cols h2::before, #projSheet.wk3d .ps-cols h3::before { content: '— '; color: rgba(92,147,255,.6); }
#projSheet.wk3d .ps-cols p { font-size: 16px; line-height: 1.7; color: #C6CBD0; max-width: 62ch; }
#projSheet.wk3d .ps-gallery .ps-g { background: #0B0E12; border: 1px solid rgba(198,203,208,.12);
  border-radius: 12px; }
#projSheet.wk3d .ps-note { color: #7D858E; }


/* ═══ v97d — STUDIO MINIMAL (2026-07-22) ═══
   Road out· CTA out· 2 παράγραφοι (P1+P3)· το κείμενο κεντραρισμένο στη μέση
   του φύλλου (deck sheet ≈ 100vh). */
#about { display: flex; align-items: center; min-height: 100vh; }
#about .wrap { grid-template-columns: 1fr; justify-items: center; width: 100%; }
#about .wrap > div[data-parallax] { text-align: center; }
#about .eyebrow { justify-content: center; }   /* flex — δεν ακούει το text-align */
#about h2.h2-cut { justify-content: center; }
#about p { margin-left: auto; margin-right: auto; }
#about .about-note { text-align: center; margin-top: 48px; }


/* ═══════════════════════════════════════════════════════════════════════════
   v98b — MOBILE PASS (2026-07-24 · Κώστας: «κινητό all over the place»)
   Root cause: το planetary 3D + το sliding deck (desktop scroll choreography)
   έτρεχαν ΚΑΙ στο κινητό. Τώρα gated OFF στο JS (planetary.js: MOBILE||COARSE →
   δεν προστίθεται pl-on· main.js: seamless deck + WORK carousel off, Services
   anchor → #services). Εδώ στυλάρουμε το ΚΑΘΑΡΟ static DOM flow.
   DESKTOP ≥961px ΜΕΝΕΙ 100% ΑΝΕΓΓΙΧΤΟ — τα πάντα μέσα σε media queries.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ---- ≤960: σβήσε τα desktop-only full-height + το νεκρό 3D section ---- */
@media (max-width: 960px) {
  /* Το planetary.js κρύβει inline το #planetary στο mobile bail — αυτό είναι το
     safety net αν το script σκάσει πριν από εκείνη τη γραμμή. Το #services (που
     το pl-on θα έκρυβε) μένει ορατό, γιατί το pl-on ΔΕΝ μπαίνει στο κινητό. */
  #planetary { display: none !important; }
  html.pl-on #services { display: block !important; }

  /* Το #about ήταν 100vh centered deck sheet (global rule) — γίνε κανονικό,
     αριστερά-στοιχισμένο block στο κινητό. */
  #about { min-height: 0; display: block; }
  #about .wrap { grid-template-columns: 1fr; justify-items: stretch; width: auto; }
  #about .wrap > div[data-parallax] { text-align: left; }
  #about .eyebrow, #about h2.h2-cut { justify-content: flex-start; }
  #about p { margin-left: 0; margin-right: 0; }
  #about .about-note { text-align: left; margin-top: 28px; }

  /* ΚΡΙΣΙΜΟ FIX (v98b): το contact <select> έχει μεγάλα options
     («Rendering & animation — photorealistic stills, motion») → min-content
     width ~450px που ΔΕΝ μάζευε → όλο το page πήγαινε 507px → το κινητό έκανε
     zoom-out (γι' αυτό «looked bad»). Δέσε τα form controls + grid cells στο
     container ώστε να μη σπρώχνουν πλάτος. */
  #briefForm input, #briefForm select, #briefForm textarea {
    width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box; }
  #contact .wrap, #contact .wrap > div, .f-grid, .f-field, .c-rows, .c-row {
    min-width: 0; }
  .c-row .k { word-break: break-word; }

  /* PROOF badge (v98b fix): το sheen ::after (translateX 130%) + το 3D
     badgeFloat rotateY έβγαιναν ~90px εκτός → οριζόντιο scroll (body 483px).
     Κλείσε το sheen μέσα στο badge (έτσι κι αλλιώς εκεί σαρώνει) + clip το
     section. Desktop ανέγγιχτο (πλατύ layout το απορροφά). */
  .badge-wrap { overflow: hidden; }
  #proof, #about, #hero { overflow-x: clip; }

  /* defensive: ουδετεροποίησε το deck stacking αν ποτέ πέσει η class σε phone */
  html.deck-on #sheetIntro, html.deck-on #work, html.deck-on #about,
  html.deck-on #contact, html.deck-on #proof, html.deck-on footer {
    position: static; top: auto; border-radius: 0; box-shadow: none; }
}

/* ---- ≤768: το phone layout ---- */
@media (max-width: 768px) {
  :root { --pad: 60px; }                  /* πιο σφιχτό section rhythm στο κινητό */
  html { scroll-behavior: auto; }         /* native anchor jumps, χωρίς jank */
  body { background-attachment: scroll; } /* iOS perf: όχι fixed-bg repaint */

  /* NAV — logo + CTA μόνο (τα mono links δεν χωράνε)· καθαρό.
     v98b: compact CTA (drop arrow, smaller pad/tracking) ώστε το «Start a
     project» να χωράει δίπλα στο logo σε ≤390px χωρίς clip. */
  .nav-in { height: 60px; }
  /* v98o: ο nav πέφτει σε 61px (60 + 1px border) ⇒ το anchor offset ακολουθεί.
     57 = 61 − 4 (ίδιο tuck με desktop). Χωρίς αυτό το 65 άφηνε +4px λωρίδα στο κινητό. */
  #hero, #planetary, #process-flow, #services, #work, #about, #contact, #proof { scroll-margin-top: 57px; }
  .nav-links { gap: 0; }
  .nav-links li:not(:last-child) { display: none; }
  .nav-cta { padding: 9px 13px !important; font-size: 10.5px !important; letter-spacing: .05em !important; gap: 0 !important; }
  .nav-cta .arr { display: none; }
  .logo svg { width: 116px; height: auto; }

  /* HERO — 3D lettermark πάνω, copy κάτω· άνετα μεγέθη */
  #hero { padding: 88px 0 44px; }
  #hero .hero-grid, .hero-grid { grid-template-columns: 1fr; gap: 22px; }
  .hero-canvas-wrap { order: -1; width: min(72vw, 340px); max-height: 40vh; margin: 0 auto; }
  .hero-copy { max-width: none; }
  .hero-meta { margin-bottom: 18px; }
  #hero h1, .hero-copy h1 { font-size: clamp(32px, 8.6vw, 46px); line-height: 1.0; }
  .hero-sub { margin-top: 20px; font-size: 16.5px; max-width: none; }
  .hero-sub .hs2 { margin-top: 10px; }

  /* SERVICES — μία στήλη κάρτες (η παρουσίαση services στο κινητό) */
  .lead-grid, .sup-grid { grid-template-columns: 1fr; gap: 14px; margin-bottom: 14px; }
  .svc { padding: 24px 22px 22px; }
  .sec-head { margin-bottom: 34px; gap: 14px; }
  .sec-head h2 { font-size: clamp(30px, 8vw, 40px); }
  .svc-note { font-size: 13.5px; }

  /* PROCESS band — vertical rail ήδη ≤640· σφίξε spacing */
  #process-flow { padding: 40px 0; }

  /* INTRO — graphic μετά κείμενο, πιο σφιχτά */
  #intro .wrap { gap: 28px; }
  .intro-side { min-height: 200px; }
  .intro-body p { font-size: clamp(19px, 5vw, 23px); }

  /* WORK — stock κάρτες, στοίβα μία στήλη */
  .work-grid { grid-template-columns: 1fr; gap: 14px; }

  /* CONTACT — info μετά form, μονή στήλη πεδία */
  #contact .wrap { gap: 34px; }
  #contact h2 { font-size: clamp(30px, 8vw, 44px); }
  .c-row { grid-template-columns: 96px 1fr; gap: 12px; }
  form { padding: 22px 20px; }
  .f-grid { grid-template-columns: 1fr; }

  /* PROOF — cred μετά badge */
  .proof-body { gap: 30px; }
  .proof-head h2 { font-size: clamp(30px, 8vw, 44px); }

  /* FOOTER — στοίβαξε τις 3 στήλες */
  footer { padding: 36px 0; }
  footer .wrap { grid-template-columns: 1fr; gap: 22px; text-align: center; justify-items: center; }
  footer ul { flex-wrap: wrap; justify-content: center; gap: 16px 22px; }
  footer .f-meta { text-align: center; }
}

/* ---- ≤560: extra squeeze ---- */
@media (max-width: 560px) {
  .wrap { padding: 0 18px; }
  #hero h1, .hero-copy h1 { font-size: clamp(30px, 9vw, 40px); }
  .hero-canvas-wrap { width: min(80vw, 300px); max-height: 36vh; }
  .sec-head h2, #contact h2, .proof-head h2 { font-size: clamp(28px, 9vw, 36px); }
  .svc { padding: 22px 18px 20px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   v9.20 (2026-07-24) — MOBILE STATIC HERO
   ─────────────────────────────────────────────────────────────────────────────
   Phones and touch devices never load three.js / gsap / ScrollTrigger / lenis
   (~740KB — see the desktop-only loader in preview.html). The WebGL lettermark
   is replaced by a drawn plate; the headline keeps the EXACT desktop treatment
   (.l1 sheen · .l2 blue→cyan flow · .l3 graphite stroke) — that markup is
   shared, nothing here touches it beyond size.

   ⚠ THE GATE BELOW MUST STAY IDENTICAL to main.js's `MOBILE || COARSE`
     (max-width:960px | pointer:coarse) and to the loader gate in preview.html.
     If they drift, a coarse-pointer tablet at 1000px gets neither 3D nor plate.

   DESKTOP ≥961px + fine pointer: nothing in this block applies. 3D untouched.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ══ v98e · STATIC HERO POSTER (`.hero-poster`) ══════════════════════════════
   A capture of the desktop three.js lockup — same scene, same camera, same
   colours (see the note in preview.html). It is placed at the geometry the
   WebGL canvas itself produces, measured rather than eyeballed:

     width  = 45.9% of the slot box · stable across 1280→1920. `fit()` scales the
              lockup into a SQUARE slot, so the binding side never switches and
              the lockup stays linear in slot size.
     top    = 22.6% of the slot box · stable.
     centre = slot centre − 0.07 × canvas width. The hero canvas spans the full
              viewport width, so that is exactly −7vw.

   The exported crop keeps ~4 CSS-px of padding per side (888×1550 buffer px at
   the 3× capture ⇒ 296×516.7 CSS px around a 288-px lockup), which is why the
   numbers below read 47.2% / 22.17% rather than 45.9% / 22.65%.

   THREE PATHS, ONE ELEMENT:
     desktop + GPU   → paints first (LCP), then cross-fades out under the live
                       canvas the moment the hero renders (html.v3d-live)
     desktop, no GPU → stays: it IS the hero
     phone           → stays: it IS the hero (replaces the v9.20 drawn plate)
   ═══════════════════════════════════════════════════════════════════════════ */
.hero-poster {
  position: absolute; top: 22.17%; left: 50%;
  width: 47.2%; height: auto;
  transform: translateX(-50%) translateX(-7vw);
  pointer-events: none; -webkit-user-select: none; user-select: none;
  transition: opacity .3s linear;
}
html.v3d-live .hero-poster { opacity: 0; }

/* No 3D anywhere on this machine (phone, coarse pointer, or no GPU): the canvas
   can never get a context, so take it out of the layout entirely. */
html.no3d #heroCanvas { display: none; }

/* ── v98e · STATIC BACKGROUND GRID ──────────────────────────────────────────
   Same capture trick: the site's own parametric wave mesh, photographed at rest
   from the desktop scene and painted as the background of the very canvas
   element that would otherwise draw it. Zero new DOM, zero new JS, and it
   inherits .mesh-bg's existing `position:fixed; inset:0; z-index:-1`.
   `cover` on the 2000×2000 source lands ≈28.7 CSS-px cells on a 390-px phone —
   desktop parity is ≈29. */
html.no3d .mesh-bg {
  background-image: url("assets/mesh-bg.webp");
  background-size: cover; background-position: center; background-repeat: no-repeat;
}

.hero-plate { display: none; }               /* v9.20 drawn plate — retired by the poster */

@media (max-width: 960px), (pointer: coarse) {
  /* the WebGL canvas never gets a context here — take it out of the layout.
     (html.no3d above covers the same case; this is the no-JS safety net.) */
  #heroCanvas { display: none; }

  /* …and the no-JS safety net for the static grid. */
  .mesh-bg {
    background-image: url("assets/mesh-bg.webp");
    background-size: cover; background-position: center; background-repeat: no-repeat;
  }

  /* «13 ⌐ 37 DESIGN STUDIO» eyebrow: on mobile it sat right above a plate that
     says the same thing, under a nav logo that says it a third time. Dropped
     on Κώστας's call (v9.20). Desktop keeps it — there it reads as an eyebrow
     to the 3D scene, not a duplicate. */
  .hero-meta { display: none; }

  /* v98j: the 3D render icon reads fine a touch smaller on the static flow —
     keeps each card's copy above the fold on a phone. */
  /* v98o: ίδιο σκεπτικό με το desktop — θήκη 118 = 84 × 1.40 (το μέγιστο --s), το img
     κρατάει το παλιό base 84 ⇒ κανένα icon δεν αλλάζει μέγεθος, απλά χωράνε όλα μέσα
     και κεντράρονται. Margins 16/12 → 8/6 για να μη φουσκώσει η κάρτα. */
  .ic3d { width: 118px; height: 118px; margin: 8px 0 6px; }
  .ic3d img { width: 84px; height: 84px; }

  /* planetary.js is not loaded here (see preview.html), so its inline hide can
     no longer run — the ≤960 rule above only covers width. This carries the
     coarse-pointer >960 case and keeps the DOM #services grid as the content. */
  #planetary { display: none !important; }
  html.pl-on #services { display: block !important; }

  /* v98e: the slot is no longer a square frame — it is just the box the poster
     stands in, so it takes the poster's portrait proportion. Height-driven so
     the lockup reads at a constant physical size and the CTAs keep their place
     on the fold. Overrides the ≤768 / ≤560 wrap sizing above by source order. */
  #hero .hero-grid, .hero-grid { grid-template-columns: 1fr; gap: 22px; }
  #hero .hero-canvas-wrap, .hero-canvas-wrap {
    order: -1; width: 100%; aspect-ratio: auto;
    height: min(42vh, 340px); max-height: none; margin: 0 auto; }

  /* the desktop placement maths (−7vw nudge, 47.2% of a square slot) is a
     desktop concern; here the poster simply owns the slot. */
  .hero-poster {
    position: static; display: block;
    width: auto; height: 100%; max-width: 100%;
    margin: 0 auto; transform: none; opacity: 1; }

  /* ── headline: desktop scale, desktop treatment ────────────────────────── */
  /* Same 48px cap and .95 leading as desktop (#hero h1). 10.8vw keeps the
     widest line («MORE THAN») at ~92% of the v98g content box (28px padding)
     down to 320px, so the three .hwrap blocks stay three lines and nothing can
     push the page wide. (v98g: was 11.6vw against the old 18px padding.) */
  #hero h1, .hero-copy h1 { font-size: clamp(32px, 10.8vw, 48px); line-height: .95; }

  /* ── v98g — TEXT INSIDE THE ANIMATED BORDERS (Κώστας 2026-07-24) ───────── */
  /* Root cause: the techframe was drawn at a fixed 46px inset (animation-config)
     while .wrap padding here is 18-38px → every hero text crossed the side rails
     by up to 28px/side. Fix at the CAUSE, not the font: the rails move to 12px
     on this gate (ANIM.techframe.insetXMobile, drawn in main.js) and the copy
     clears them — 28px padding = 12px rail + 16px breathing room. */
  #hero .wrap { padding-left: 28px; padding-right: 28px; }

  /* ── v98h — PROCESS: tap-to-expand station details (Κώστας 2026-07-25) ─── */
  /* The desktop hover panel (pf-desc, gsap) never runs here — each station gets
     its own detail block right below it instead, same content as pfRender.
     Elements exist ONLY on this gate (created in buildProcessFlow under
     MOBILE||COARSE) → desktop DOM & geometry untouched. display toggle +
     entry keyframe (no gsap on this path)· colors are existing tokens via
     var() — no new hex. flex-wrap lets the full-width detail drop BELOW the
     row on the 641-960 horizontal band· on the ≤640 vertical rail it flows
     naturally under its station. */
  .pf-track { flex-wrap: wrap; }
  .pf-mdetail { display: none; width: 100%; padding: 2px 0 6px; }
  .pf-mdetail.open { display: block; animation: pfmdIn .3s ease both; }
  .pf-mdetail .n { font-family: var(--mono); font-size: 12.5px; color: var(--blue); letter-spacing: .06em; }
  .pf-mdetail h3 { font-family: var(--disp); font-size: 17px; font-weight: 700; letter-spacing: -.01em;
    text-transform: uppercase; color: var(--space-900); margin: 4px 0 6px; }
  .pf-mdetail p { font-size: 14.5px; line-height: 1.6; color: var(--graphite-600); max-width: 62ch; margin: 0; }
  .pf-mdetail .keytag { display: block; width: fit-content; margin: 8px 0 0; font-family: var(--mono);
    font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--space-900);
    background: var(--volt); border: 1px solid var(--space-900); border-radius: 3px; padding: 2px 7px; }
  /* v98m — 3D icons on the touch path. Two things the desktop rules get wrong
     here: (1) the scroll-driven .pf-active never fires without gsap, so the
     icons would sit at their dimmed rest opacity forever — they go to full;
     (2) the vertical rail must pass BEHIND the parts, same as the horizontal
     one. Slightly smaller box: a 88px part next to 15px label text reads
     top-heavy in a column. */
  .pf-track.pf-3d .pf-chip3d { width: 72px; height: 72px; }
  .pf-track.pf-3d .pf-chip3d img { width: 72px; height: 72px; }
  .pf-track.pf-3d .pf-line { z-index: 0; }
  .pf-track.pf-3d .pf-node { z-index: 2; }

  /* on the vertical rail, indent under the label column (chip 56px + gap 14px)
     so the dotted rail line at left stays clear of the text */
  @media (max-width: 640px) {
    .pf-mdetail { padding-left: 86px; }   /* v98m: chip 72 + gap 14 */
  }

  /* ── v98i — CLS: reserve the hero's final footprint on phones ──────────── */
  /* Pre-hydration the data-bind texts are EMPTY, so #hero paints collapsed and
     #sheetIntro sits inside the first viewport; when main.js lands (late on
     PSI's throttled 4G) it fills the copy and the whole deck jumps — one
     0.26 layout shift attributed to #sheetIntro (measured deterministically,
     3 local runs + live). With the hero holding ≥1 viewport from the first
     paint, #sheetIntro stays below the fold while hydration runs → the shift
     never intersects the viewport and scores 0. Phones only: on the 641-960
     band the natural hero can be shorter than the viewport and this would add
     visible dead space. Fast connections were already 0 — this pins the slow
     path to the same number. */
  @media (max-width: 640px) {
    /* justify-content:start kills the second half of the jump: the base #hero
       is a centering flex column (style.css:91), so the half-empty pre-hydration
       grid sat at y=214 and slid to y=88 when the copy landed. Top-aligned, the
       grid paints at its final y from the first frame. Visually nil at rest:
       the hydrated hero fills the reserved viewport anyway. */
    #hero { min-height: 100vh; min-height: 100svh; justify-content: flex-start; }
  }
}
@keyframes pfmdIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

/* ════ v98m — CERTIFICATION BADGES (foot of the receipts card) ═══════════════
   The badges ship pre-cropped (white outer frame eroded off the alpha), so no
   masking is needed here — they only need laying out. Roughly half the large
   CSWE badge, which keeps its own size.
   rev4: moved OUT of the <details> to the bottom of the card. A hairline above
   separates them from the credential lines without adding another box. */
/* v98s — ΔΙΟΡΘΩΣΗ. Το προηγούμενο `display:flex; flex-wrap:nowrap` με `flex: 0 1 104px`
   ΣΤΗΡΙΖΟΤΑΝ ΣΤΟ SHRINK — και το shrink ΔΕΝ ΕΝΕΡΓΟΠΟΙΟΥΝΤΑΝ ΠΟΤΕ. Τα <img> γράφονται
   από το main.js με HTML attributes width/height = 104 (για CLS 0)· αυτό δίνει στο flex
   item «specified size suggestion» 104px, που γίνεται το content-based minimum του — το
   `min-width:0` στο img ΔΕΝ το ακυρώνει για replaced element. Αποτέλεσμα, ΜΕΤΡΗΜΕΝΟ
   headless πάνω στο v98r bundle (badges φορτωμένα, <details> ΚΛΕΙΣΤΟ):

     viewport   .proof-body col   .cred     .cert-badges   ανά badge   κομμένο
     390 mob         354          602            544          84       +230px  ← ΤΟ BUG
     768 tab         707          742            684         104         +5px
     1280           1184          742            684         104           ok
     1920           1654          883            825         104           ok

   Η ρίζα: min-content του `.cert-badges` = 6×84 + 5×8 = 544. Το `.cred` είναι grid item
   με `min-width:auto` ⇒ δεν συμπιέζεται κάτω από το min-content του παιδιού του ⇒ 602px
   μέσα σε κολόνα 354px. Το `#proof { overflow-x: clip }` έκρυβε τη ζημιά (pageOvf = 0
   παντού), γι' αυτό πέρασε απαρατήρητο στο desktop: εκεί το κόψιμο πέφτει εκτός κάρτας.

   Η λύση: grid με ΡΗΤΟ αριθμό στηλών αντί για shrink. Το `minmax(0,1fr)` αφήνει τα
   tracks να μικρύνουν όσο χρειαστεί, το `max-width` στο img κρατά το ταβάνι των 104px,
   και το `max-width` στο grid κλειδώνει το desktop στην εγκεκριμένη γραμμή των 6.
   ⚠ ΟΧΙ `justify-content:center` / auto margins εδώ — είναι η παγίδα που στο v98q
   κατέρρευσε το `.wrap` σε fit-content. */
.cert-badges { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px;
  align-items: start; justify-items: start; max-width: 684px;   /* 6×104 + 5×12 */
  margin: 22px 0 0; padding-top: 20px; border-top: 1px solid var(--silver-300, rgba(11,14,18,.10)); }
.cert-badges:empty { display: none; padding: 0; border: 0; margin: 0; }
.cert-badges img { width: 100%; max-width: 104px; min-width: 0; height: auto; display: block;
  transition: transform .28s cubic-bezier(.2,.7,.2,1), filter .28s; }
.cert-badges img:hover { transform: translateY(-3px) scale(1.05);
  filter: drop-shadow(0 8px 14px rgba(11,14,18,.20)); }
/* Κινητό: 3+3 αντί για 6 στη σειρά. Έξι σε μία γραμμή στα 390px σημαίνει 47px/badge —
   δυσανάγνωστο. Δύο ΣΥΜΜΕΤΡΙΚΕΣ σειρές των 3 διαβάζονται ως πλέγμα, όχι ως λάθος
   (το «five-plus-one» που απέρριπτε το v98m ήταν ασύμμετρο· το 3+3 δεν είναι).
   Στα 390px: κολόνα 354 − 2×28 padding = 298 ⇒ (298 − 2×8)/3 = 94px ανά badge. */
@media (max-width: 640px) {
  .cert-badges { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; max-width: 328px; }
  /* Συνέπεια του `min-width:0` στο `.proof-body > *`: η κάρτα δεν φουσκώνει πια, άρα ό,τι
     ήταν «κρυφά φαρδύ» μέσα της πρέπει τώρα να χωράει μόνο του. Ο πίνακας πιστοποιήσεων
     (auto layout, min-content 544px) ξεχείλιζε μόλις ανοίξει το <details>. `fixed` +
     ρητά ποσοστά κλειδώνουν τις δύο στήλες, `anywhere` σπάει τον κωδικό C-XXXXXXXXXX
     που δεν έχει σημείο να σπάσει από μόνος του. */
  .cred table { table-layout: fixed; }
  .cred td { font-size: 10.5px; padding: 6px 0; }
  .cred td:first-child { width: 56%; padding-right: 8px; }
  .cred td:last-child { width: 44%; overflow-wrap: anywhere; }
}
