/* ── Gallery viewport ── */
#viewport {
  position: fixed;
  inset: 0;
  overflow: hidden;
  cursor: grab;
  user-select: none; -webkit-user-select: none;
  touch-action: none;
}
#viewport.dragging { cursor: grabbing; }
#world {
  position: absolute; top: 0; left: 0;
  transform-origin: 0 0;
  will-change: transform;
}

/* ── Module ── */
.module {
  position: absolute;
  width: var(--mod-img, 200px);
  height: var(--mod-img, 200px);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
  transform-origin: center center;
  transition: transform 0.28s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  cursor: pointer;
}
/* While dragging the canvas, keep the grabbing cursor even over modules */
#viewport.dragging .module { cursor: grabbing; }
/* Live color adjustment (brightness/contrast/saturation), tuned via /admin/
   and applied instantly through these custom properties. Defaults = no-op. */
:root {
  --mod-brightness: 100%;
  --mod-contrast: 100%;
  --mod-saturate: 100%;
}
.module-thumb,
.module-video {
  display: block;
  flex-shrink: 0;
  pointer-events: none;
  background: transparent;
  object-fit: contain;
  filter: url(#eidos-color-filter) brightness(var(--mod-brightness)) contrast(var(--mod-contrast)) saturate(var(--mod-saturate));
}
/* Mobile browsers, especially Safari, can shift colors even when an SVG LUT
   is configured as an identity filter. Bypass the filter entirely so mobile
   thumbnails and hover videos use the same source colors as desktop. */
html.is-mobile .module-thumb,
html.is-mobile .module-video {
  filter: none;
}
/* At rest only the WebP thumb shows; the video is swapped in once it is ready */
.module-video { display: none; }
.module.video-active .module-thumb { display: none; }
.module.video-active .module-video { display: block; }

/* Discourage casual saving of module sources (right-click / long-press / drag).
   Note: this only blocks the default browser menus — it cannot fully prevent
   access via devtools, network tab, or direct URLs. */
.module,
.module-thumb,
.module-video,
#mod-detail-video,
#mod-overlay-content img,
#mod-overlay-content video {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
  user-drag: none;
}

/* ── Module hover label ── */
#hover-label {
  position: fixed;
  pointer-events: none;
  z-index: 9998;
  font-family: 'Roboto Mono', monospace;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.02em;
  color: #fff;
  mix-blend-mode: difference;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.12s ease;
  will-change: transform;
}
#hover-label.visible { opacity: 1; }


/* ── Signus Digital Round font ── */
@font-face {
  font-family: 'Signus Digital Round';
  src: url('../assets/fonts/SignusDigitalRoundNbp-A61D.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}

/* ── Module Detail Overlay ── */
#mod-overlay {
  position: fixed;
  inset: 0;
  z-index: 600;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.28s ease;
}
#mod-overlay.open {
  pointer-events: auto;
  opacity: 1;
}

#mod-overlay-bg {
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.90);
}
/* Chrome drops the alpha detail video onto a hardware overlay plane that
   doesn't composite correctly under backdrop-filter, producing a visible
   seam at the video's bounds. Safari doesn't hit that bug, so restore the
   blur there only (.is-safari is set on <html> via IS_SAFARI in main.js). */
html.is-safari #mod-overlay-bg {
  background: rgba(255, 255, 255, 0.70);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

#mod-overlay-glow {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translate(-50%, 55%) scale(0.45);
  transform-origin: 50% 100%;
  opacity: 0;
  /* Opacity settles quickly so the circle is already visible while it's
     still visibly growing — fading and scaling on the same timeline made
     the growth read as a simple fade instead of a spread. */
  transition: opacity 0.5s ease, transform 1.1s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: opacity, transform;
  /* 화면이 작아질수록 원이 커짐: 200vw가 1500px 상한을 초과하면 1500px로 고정 */
  width: clamp(1200px, 240vw, 2300px);
  height: clamp(1000px, 200vw, 1900px);
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 50%, #187CFF 0%, rgba(0, 212, 255, 0) 100%);
  background: radial-gradient(
    50% 50% at 50% 50%,
    color(display-p3 0.094 0.486 1) 0%,
    color(display-p3 0 0.831 1 / 0) 100%
  );
  z-index: 1;
  pointer-events: none; /* 오버레이 닫혀있을 때 이벤트 차단 */
}
/* Keep the current large-screen glow proportions, but scale the whole ellipse
   down from whichever desktop viewport axis becomes constrained first. */
@media (min-width: 769px) {
  #mod-overlay-glow {
    width: min(2762px, 134.4vw, 268.8vh);
    height: auto;
    aspect-ratio: 5 / 4;
  }
}
#mod-overlay.open #mod-overlay-glow {
  opacity: 1;
  transform: translate(-50%, 55%) scale(0.95);
  pointer-events: auto; /* 오버레이 열렸을 때만 클릭으로 닫기 허용 */
}

#mod-overlay-content {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Prevent text selection/drag on the overlay code area + title */
#mod-detail-header,
#mod-detail-title {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

#mod-detail-header {
  position: absolute;
  top: clamp(80px, 12vh, 140px);
  left: 50%;
  transform: translate(-50%, 10px);
  z-index: 4;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 11px;
  opacity: 0;
  transition: opacity 0.52s ease, transform 0.52s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: opacity, transform;
}

.mod-detail-bar {
  display: block;
  width: 4px;
  height: 20px;
  background: #187CFF;
  background: color(display-p3 0.094 0.486 1);
  flex-shrink: 0;
  transform: translateY(-0.5px);
}

.mod-detail-code-block {
  display: flex;
  align-items: center;
  gap: 7px;
}

#mod-detail-compact {
  font-family: 'Signus Digital Round', monospace;
  font-size: 34px;
  font-weight: normal;
  color: #187CFF;
  color: color(display-p3 0.094 0.486 1);
  -webkit-text-stroke: 1.0px #187CFF;
  -webkit-text-stroke: 1.0px color(display-p3 0.094 0.486 1);
  letter-spacing: 0;
  line-height: 1;
}

.mod-detail-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

#mod-detail-prdt-line,
#mod-detail-name-line {
  font-family: 'Roboto Mono', monospace;
  font-size: 10px;
  font-weight: 400;
  color: #187CFF;
  color: color(display-p3 0.094 0.486 1);
  letter-spacing: 0.07em;
  line-height: 1.1;
}

#mod-detail-title {
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: clamp(48px, 7vw, 110px);
  font-weight: 700;
  color: #187CFF;
  color: color(display-p3 0.094 0.486 1);
  text-align: center;
  line-height: 1;
  letter-spacing: -0.03em;
  margin: 0;
  word-break: normal;
  overflow-wrap: break-word;
  position: absolute;
  top: clamp(122px, calc(12vh + 42px), 182px);
  left: 0;
  right: 0;
  z-index: 3;
  max-width: 96vw;
  margin-inline: auto;
  padding: 0 clamp(12px, 3vw, 40px);
  box-sizing: border-box;
  cursor: pointer;
  opacity: 0;
  transform: translateY(24px);
  /* Opacity settles well before the transform finishes, so the title is
     still visibly sliding up after it's already fully readable — otherwise
     the motion reads as a plain fade instead of a rise. */
  transition: opacity 0.4s ease 0.05s, transform 0.85s cubic-bezier(0.16, 1, 0.3, 1) 0.05s;
  will-change: opacity, transform;
}

#mod-detail-video {
  position: relative;
  z-index: 4;
  --detail-video-scale: 1;
  --detail-video-y: 0px;
  width: calc(clamp(460px, 82vmin, 1000px) * var(--detail-video-scale));
  height: calc(clamp(460px, 82vmin, 1000px) * var(--detail-video-scale));
  object-fit: contain;
  display: block;
  pointer-events: none;   /* interactions handled on #mod-overlay-content */
  cursor: default;
  opacity: 0;
  transform: translateY(calc(12px + var(--detail-video-y))) scale(0.99);
  transition: opacity 0.58s ease 0.05s, transform 0.58s cubic-bezier(0.16, 1, 0.3, 1) 0.05s;
  will-change: opacity, transform;
}
#mod-overlay.content-ready #mod-detail-header {
  opacity: 1;
  transform: translate(-50%, 0);
}
#mod-overlay.content-ready #mod-detail-title {
  opacity: 1;
  transform: translateY(0) scale(1);
}
#mod-overlay.content-ready #mod-detail-video {
  opacity: 1;
  transform: translateY(var(--detail-video-y)) scale(1);
}
/* CE-category modules render slightly smaller in the detail overlay. */
#mod-overlay.category-ce #mod-detail-video {
  --detail-video-scale: 0.88;
}
/* CE-H-1 sits slightly lower than other modules in the detail overlay. */
#mod-overlay.module-ce-h-1 #mod-detail-video {
  --detail-video-y: 28px;
}
/* Title and video visually overlap in the center of the screen — clicking
   either brings it above the other (see the click handlers in main.js). */
#mod-overlay-content.detail-title-front #mod-detail-title { z-index: 10; }
#mod-overlay-content.detail-title-front #mod-detail-video { z-index: 3; }
/* Cursor over the overlay video pause zone (inner 70%) */
#mod-overlay-content.over-pause-zone { cursor: grab; }
#mod-overlay-content.grabbing { cursor: grabbing; }

/* Prev/next arrows — step through modules within the same category. */
.mod-nav-btn {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  width: auto;
  height: auto;
  border: none;
  border-radius: 50%;
  padding: 14px;
  /* #1B3E6C at 30% alpha — only the background is translucent so the white
     icon on top stays fully opaque, instead of fading the whole button. */
  background: rgba(27, 62, 108, 0.3);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 5;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease 0.1s, background 0.2s ease;
  -webkit-tap-highlight-color: transparent;
}
.mod-nav-btn:hover { background: rgba(36, 72, 124, 0.45); }
.mod-nav-btn img {
  width: 22px;
  height: 22px;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}
/* Keep the tablet button artwork unchanged while enlarging its invisible
   touch target by 20% in both dimensions. */
html.is-tablet .mod-nav-btn::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 120%;
  height: 120%;
  transform: translate(-50%, -50%);
  border-radius: inherit;
}
#mod-nav-prev { left: calc(clamp(48px, 8vw, 110px) + 48px); }
#mod-nav-next { right: calc(clamp(48px, 8vw, 110px) + 48px); }
#mod-overlay.open .mod-nav-btn {
  opacity: 1;
  pointer-events: auto;
}

@media (max-width: 768px) {
  #mod-overlay-content {
    --mobile-overlay-shift: -24px;
  }
  #mod-detail-header {
    top: calc(clamp(80px, 12vh, 140px) + var(--mobile-overlay-shift));
  }
  .mod-detail-bar { width: 3px; height: 21px; }
  #mod-detail-title {
    top: calc(clamp(122px, calc(12vh + 42px), 182px) + var(--mobile-overlay-shift));
  }
  #mod-detail-video {
    width: calc(clamp(340px, 90vw, 560px) * var(--detail-video-scale));
    height: calc(clamp(340px, 90vw, 560px) * var(--detail-video-scale));
    transform: translateY(calc(12px + var(--detail-video-y) + var(--mobile-overlay-shift))) scale(0.99);
  }
  #mod-overlay.content-ready #mod-detail-video {
    transform: translateY(calc(var(--detail-video-y) + var(--mobile-overlay-shift))) scale(1);
  }
  /* Below the video, side by side, instead of straddling the viewport. */
  .mod-nav-btn {
    width: 52px;
    height: 52px;
    padding: 0;
    top: calc(50% + clamp(170px, 45vw, 280px) + 20px + var(--mobile-overlay-shift));
    transform: none;
  }
  .mod-nav-btn img { width: 18px; height: 18px; }
  #mod-nav-prev { left: calc(50% - 64.5px); right: auto; }
  #mod-nav-next { left: calc(50% + 12.5px); right: auto; }
}

/* Logo white + nav hidden when overlay is open */
#logo-btn img { transition: filter 0.28s ease; }
body.mod-overlay-open #logo-btn img { filter: brightness(0) invert(1); }
body.mod-overlay-open #main-nav { opacity: 0; pointer-events: none; transition: opacity 0.28s ease; }
#main-nav { transition: opacity 0.28s ease; }
#main-nav .nav-link { color: #ffffff; }

/* ── Category menu (top-right) ─────────────────────────────────────────────── */
#menu-wrap {
  position: fixed;
  top: max(24px, constant(safe-area-inset-top));
  top: max(24px, env(safe-area-inset-top, 24px));
  right: max(24px, constant(safe-area-inset-right));
  right: max(24px, env(safe-area-inset-right, 24px));
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  mix-blend-mode: difference;
  transition: opacity 0.28s ease;
}
body.mod-overlay-open #menu-wrap { opacity: 0; pointer-events: none; }

#menu-btn {
  position: relative;
  width: 20px;
  height: 18px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.menu-line {
  position: absolute;
  left: 0;
  width: 20px;
  height: 2px;
  background: #ffffff;
  transform-origin: center;
  transition: transform 0.35s cubic-bezier(0.65, 0, 0.35, 1), opacity 0.25s ease;
}
.menu-line-1 { top: 0; }
.menu-line-2 { top: 8px; }
.menu-line-3 { top: 16px; }
#menu-btn.open .menu-line-1 { transform: translateY(8px) rotate(45deg); }
#menu-btn.open .menu-line-2 { opacity: 0; }
#menu-btn.open .menu-line-3 { transform: translateY(-8px) rotate(-45deg); }

#category-menu {
  margin-top: 16px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: max-height 0.45s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease;
}
#category-menu.open {
  max-height: 420px;
  opacity: 1;
  pointer-events: auto;
}
.category-link {
  font-family: 'helvetica-neue-lt-pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-size: 17px;
  font-weight: 400;
  letter-spacing: 0.00em;
  line-height: 1.3;
  color: #7f7f7f;
  text-decoration: none;
  cursor: pointer;
  user-select: none; -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
  transition: color 0.25s ease;
}
.category-link:hover { color: #ffffff; }
.category-link.active { color: #ffffff; }
@media (max-width: 768px) {
  .category-link { font-size: 19px; }
  #category-menu { gap: 8px; }
}
