/* index.css — Open, Breathing Creative Portfolio for Abdulrezak Hamud */

@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Syne:wght@700;800;900&family=Inter:wght@400;500;600;700;800&family=Poppins:wght@400;500;600;700;800&family=Montserrat:wght@400;500;600;700;800&family=Playfair+Display:wght@400;500;600;700;800&family=Oswald:wght@400;500;600;700&family=Roboto+Slab:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&family=Bebas+Neue&family=Work+Sans:wght@400;500;600;700;800&family=DM+Sans:wght@400;500;600;700;800&display=swap');

:root {
  --bg: #060709;
  --accent: #00F2FE;
  --accent-alt: #9D4EDD;

  --text-primary: #F8FAFC;
  --text-secondary: #94A3B8;
  --text-faint: #3F4759;

  --border: rgba(255, 255, 255, 0.07);
  --border-hover: rgba(255, 255, 255, 0.22);

  --font-display: 'Syne', sans-serif;
  --font-body: 'Plus Jakarta Sans', sans-serif;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);

  --page-pad: 72px;
}

*, *::before, *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  background: var(--bg);
  color: var(--text-primary);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Do not show the HTML starter content while the live site data is loading. */
.homepage-loader {
  display: none;
}

body.homepage-loading > *:not(#homepageLoader) {
  visibility: hidden;
}

body.homepage-loading #homepageLoader,
body.homepage-load-error #homepageLoader {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--bg);
  color: var(--text-secondary);
  font: 600 0.75rem/1.4 var(--font-body);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-align: center;
}

body.homepage-load-error #homepageLoader {
  color: #ff7b8b;
}

body.homepage-ready #homepageLoader {
  display: none;
}

/* CUSTOM CURSOR */
.cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 10px;
  height: 10px;
  background: var(--accent);
  border-radius: 50%;
  pointer-events: none;
  z-index: 9999;
  will-change: transform;
  transition: width 0.3s var(--ease), height 0.3s var(--ease), opacity 0.3s ease;
  mix-blend-mode: screen;
}

.cursor.expanded {
  width: 56px;
  height: 56px;
  background: rgba(0, 242, 254, 0.15);
  border: 1px solid var(--accent);
}

/* Touch devices have no real pointer to trail — without this the dot just
   sits frozen whatever its last (usually initial, top-left) position was,
   visible but useless, since mousemove never fires from a touch scroll. */
@media (hover: none) {
  .cursor { display: none; }
}

/* Real-mouse devices: hide the native OS cursor so only ours shows, scoped
   to pages that actually have #cursor in their markup (every public page)
   so this can never leave an admin page — which never included the custom
   cursor markup or script — with no visible cursor at all. The `*` +
   !important is needed because plenty of elements site-wide (buttons,
   pills, tiles) set their own explicit `cursor: pointer`, which — being a
   direct declaration rather than an inherited one — would otherwise win
   back over a plain `body { cursor: none }` the moment the pointer is
   actually over something clickable, which is exactly when it matters most.
   :not(.cursor-disabled) is the admin off-switch (Dashboard → Theme →
   "Custom cursor effect") — deliberately excluded from the selector itself
   rather than "fixed" with a second competing rule: :has()'s specificity is
   inherited from its argument, so :has(#cursor) is ID-level specificity
   (same as #cursor itself) and would always beat a plain .cursor-disabled
   class rule regardless of source order — this way there's nothing to win
   against, the rule simply doesn't match at all when disabled. */
@media (hover: hover) and (pointer: fine) {
  body:has(#cursor):not(.cursor-disabled),
  body:has(#cursor):not(.cursor-disabled) * {
    cursor: none !important;
  }
}

/* Admin off-switch's other half — the dot itself, not just the native cursor. */
body.cursor-disabled .cursor {
  display: none;
}

/* LAYOUT */
.wrap {
  max-width: 1760px;
  margin: 0 auto;
  padding: 0 var(--page-pad);
}

/* HEADER — full-bleed, brand flush left, room on the right for a photo */
.site-header {
  padding: 40px var(--page-pad);
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 200;
  background: var(--bg);
}

.brand {
  text-decoration: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.brand-name {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text-primary);
}

.brand-role {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text-secondary);
  letter-spacing: 0.01em;
}

.nav-right {
  display: flex;
  align-items: center;
  gap: 32px;
}

/* TEXT-LINK BUTTONS — no boxes, underline sweep on hover */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: none;
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 2px 0;
  cursor: pointer;
  text-decoration: none;
  position: relative;
  transition: color 0.25s var(--ease);
}

.pill::after {
  content: '';
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transition: right 0.3s var(--ease);
}

.pill:hover {
  color: var(--text-primary);
}

.pill:hover::after {
  right: 0;
}

.pill.primary {
  color: var(--accent);
}

.pill.primary::after {
  background: var(--accent);
}

.pill.primary:hover {
  color: var(--accent);
}

/* MARQUEE — ROTATED KINETIC STRIP */
.marquee-wrap {
  overflow: hidden;
  white-space: nowrap;
  background: linear-gradient(90deg, var(--accent-alt), var(--accent));
  padding: 11px 0;
  transform: rotate(-1.2deg);
  margin: 28px -60px 56px;
}

.marquee-inner {
  display: inline-block;
  animation: ticker 28s linear infinite;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: #000;
}

/* Paused (via setupMarqueePause() in app.js) while scrolled out of view — a
   rotated, clipped element with a permanently-running animation is real,
   continuous compositor/GPU work; nothing needs to pay that cost for a
   strip nobody's currently looking at. Same reasoning as the client logos
   marquee's off-screen pause, just CSS-driven here instead of JS/rAF. */
.marquee-inner.paused {
  animation-play-state: paused;
}

@keyframes ticker {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* BANNER — a simpler, independent alternative/companion to Hero. Empty
   heading+sub collapse to nothing so an unconfigured banner takes no space
   even if the section is switched on before it's been written. */
.banner-section {
  padding: 96px var(--page-pad);
  text-align: center;
}

.banner-heading {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 4vw, 3rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  line-height: 1.1;
  max-width: 900px;
  margin: 0 auto 16px;
}

.banner-sub {
  color: var(--text-secondary);
  font-size: 1.05rem;
  max-width: 640px;
  margin: 0 auto 28px;
}

.banner-btn {
  display: inline-flex;
}

/* Banner image is optional — when absent, .banner-inner just centers the
   text column exactly like before this field existed. */
.banner-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 56px;
  flex-wrap: wrap;
}

.banner-copy {
  max-width: 640px;
}

.banner-image {
  max-width: 420px;
  width: 100%;
  border-radius: 16px;
  object-fit: cover;
}

@media (max-width: 900px) {
  .banner-inner { flex-direction: column-reverse; }
  .banner-copy { text-align: center; }
}

/* HERO — full-bleed, matches header edge padding */
.hero {
  padding: 20px var(--page-pad) 80px;
  text-align: left;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 64px;
}

.hero-copy {
  flex: 1;
  min-width: 0;
}

.hero-photo {
  position: relative;
  flex-shrink: 0;
  width: clamp(220px, 22vw, 360px);
  aspect-ratio: 3 / 4;
  border-radius: 20px;
  overflow: hidden;
}

.hero-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
  transition: transform 0.2s ease;
}

.hero-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, var(--bg) 0%, transparent 30%);
  pointer-events: none;
}

.hero-title {
  font-family: var(--font-display);
  font-size: clamp(2.8rem, 5.6vw, 4.8rem);
  font-weight: 900;
  line-height: 1.02;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  margin-bottom: 28px;
  overflow-wrap: break-word;
  word-break: break-word;
}

.line-mask {
  display: block;
  overflow: hidden;
  padding-bottom: 0.08em;
}

.hero-line {
  display: block;
  will-change: transform;
}

.hero-title .outline {
  -webkit-text-stroke: 1.5px rgba(255,255,255,0.3);
  color: transparent;
}

.hero-title .lit {
  background: linear-gradient(110deg, #fff 30%, var(--accent) 75%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.hero-sub {
  max-width: 780px;
  font-size: 1.1rem;
  color: var(--text-secondary);
  line-height: 1.75;
}

.hero-cv {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 32px;
  color: var(--text-primary);
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  text-decoration: none;
  position: relative;
  transition: gap 0.25s ease, color 0.25s ease;
}

.hero-cv::after {
  content: '';
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -4px;
  height: 2px;
  background: var(--accent);
  transition: right 0.3s var(--ease);
}

.hero-cv:hover {
  color: var(--accent);
  gap: 14px;
}

.hero-cv:hover::after {
  right: 0;
}

.hero-cv .arrow {
  color: var(--accent);
  font-family: var(--font-body);
}

/* SECTION INTRO — reused for Featured + All Projects headings */
.section-intro {
  padding: 64px 0 24px;
  border-top: 1px solid var(--border);
  text-align: center;
}

.section-intro.no-border {
  border-top: none;
  padding-top: 12px;
}

/* FILTERS — NO PANEL BOX */
.filter-section {
  padding: 24px 0 56px;
}

.filter-group {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.filter-group:last-child {
  margin-bottom: 0;
}

/* The actual row of buttons+separators inside a .filter-group — pulled out
   of inline HTML styles (index.html/homepage-preview.html/category.js all
   used to hardcode `style="display:flex; flex-wrap:wrap;"` directly on this
   div) specifically so the mobile override below can win the cascade. An
   inline style always beats a class, media query or not — the old mobile
   chip attempt silently did nothing because of exactly that. */
.filter-tabs-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}

.filter-label {
  display: none;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-faint);
  font-weight: 700;
  min-width: 80px;
}

/* DISCIPLINE — LARGE GHOST TEXT TABS */
.disc-btn {
  background: transparent;
  border: none;
  color: var(--text-faint);
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  cursor: pointer;
  padding: 0 4px;
  position: relative;
  transition: color 0.25s ease;
}

.disc-btn::after {
  content: '';
  position: absolute;
  left: 4px;
  right: calc(100% - 4px);
  bottom: -4px;
  height: 2px;
  background: var(--text-primary);
  transition: right 0.35s var(--ease);
}

.disc-btn:hover {
  color: var(--text-secondary);
}

.disc-btn.active {
  color: var(--text-primary);
}

.disc-btn.active::after {
  right: 4px;
}

.disc-sep {
  color: var(--text-faint);
  font-size: 1.5rem;
  font-family: var(--font-display);
  font-weight: 300;
}

/* NICHE — TEXT TABS, SAME LANGUAGE AS DISCIPLINE */
.niche-btn {
  background: transparent;
  border: none;
  color: var(--text-faint);
  font-family: var(--font-body);
  font-size: 0.82rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 0;
  cursor: pointer;
  position: relative;
  transition: color 0.25s ease;
}

.niche-btn::after {
  content: '';
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -3px;
  height: 1px;
  background: var(--text-primary);
  transition: right 0.3s var(--ease);
}

.niche-btn:hover {
  color: var(--text-secondary);
}

.niche-btn.active {
  color: var(--text-primary);
}

.niche-btn.active::after {
  right: 0;
}

.niche-sep {
  color: var(--text-faint);
  font-size: 0.82rem;
  font-weight: 300;
}

/* STATUS + SHARE ROW */
/* GALLERY SECTION — full bleed, no horizontal padding */
.gallery-section {
  width: 100%;
  margin-bottom: 0;
  padding: 0 var(--page-pad);
}

/* BLOG LISTING — independent card grid, deliberately not the same tile system
   as the project showcase (no shared filters, no visual coupling to projects) */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
  padding-bottom: 120px;
}

.blog-card {
  display: block;
  color: inherit;
  text-decoration: none;
}

.blog-card-thumb {
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border-radius: 12px;
  background: #0a0b0e;
  margin-bottom: 18px;
}

.blog-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.65s var(--ease);
}

.blog-card:hover .blog-card-thumb img {
  transform: scale(1.05);
}

.blog-card-date {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 8px;
}

.blog-card-title {
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  line-height: 1.3;
}

@media (max-width: 1024px) {
  .blog-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .blog-grid { grid-template-columns: 1fr; gap: 32px; }
}

/* SHOWCASE — 4-COLUMN EDGE-TO-EDGE THUMBNAIL GRID */
.showcase {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  margin-bottom: 0;
}

/* EACH TILE */
.project-entry {
  position: relative;
  cursor: pointer;
  overflow: hidden;
  aspect-ratio: 3 / 4;
}

/* META ROW — hidden in grid view, not used */
.project-top {
  display: none;
}

.project-index {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--text-faint);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.project-discipline {
  font-size: 0.78rem;
  color: var(--text-faint);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* THUMBNAIL MEDIA — fills the tile completely */
.project-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background: #0a0b0e;
  overflow: hidden;
}

/* The image itself */
.project-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  transition: transform 0.65s var(--ease), filter 0.55s ease;
  will-change: transform, filter;
}

/* On entry hover: zoom in + blur the image */
.project-entry:hover .project-media img {
  transform: scale(1.06);
  filter: blur(3px) brightness(0.55);
}

.project-media iframe {
  width: 100%;
  height: 100%;
  border: none;
  pointer-events: none;
  transition: filter 0.55s ease;
}

.project-entry:hover .project-media iframe {
  filter: blur(3px) brightness(0.55);
}

/* TITLE OVERLAY — hidden at rest, revealed on hover */
.media-title-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 40px 44px;
  z-index: 5;
  pointer-events: none;
}

.overlay-title {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 2.4vw, 2.1rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  line-height: 1.08;
  color: #fff;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
  will-change: opacity, transform;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

.overlay-sub {
  font-size: 0.85rem;
  font-weight: 600;
  color: rgba(255,255,255,0.55);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-top: 8px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.4s var(--ease) 0.05s, transform 0.4s var(--ease) 0.05s;
}

/* Reveal on hover */
.project-entry:hover .overlay-title {
  opacity: 1;
  transform: translateY(0);
}

.project-entry:hover .overlay-sub {
  opacity: 1;
  transform: translateY(0);
}

/* Small type label top-left */
.media-label {
  position: absolute;
  top: 18px;
  left: 18px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: rgba(255,255,255,0.45);
  z-index: 6;
  transition: opacity 0.3s ease;
}

.project-entry:hover .media-label {
  opacity: 0;
}

.project-footer {
  display: none;
}

.project-cta {
  display: none;
}

.details-title {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 3.5vw, 3rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  line-height: 1.05;
}

/* TOOLS STRIP */
.tools-section {
  text-align: center;
  padding: 96px 0 140px;
  border-top: 1px solid var(--border);
}

.tools-label {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-faint);
  margin-bottom: 28px;
}

.tools-list {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px 40px;
}

.tool-item {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 2.2vw, 1.9rem);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  color: var(--text-secondary);
  transition: color 0.25s ease;
}

.tool-item:hover {
  color: var(--text-primary);
}

/* CLIENT LOGOS CAROUSEL */
.logos-intro {
  text-align: center;
  padding-top: 32px;
}

.logos-marquee {
  overflow: hidden;
  white-space: nowrap;
  padding: 32px 0 96px;
}

.logos-track {
  display: inline-flex;
  align-items: center;
  gap: 72px;
  /* Position is driven by JS (setupLogosMarquee in app.js), not a CSS @keyframes
     animation — pure-CSS infinite marquees can desync or freeze after running
     for a very long time (compositor-thread animations losing sync, especially
     after the tab's been backgrounded a while); a requestAnimationFrame loop
     computed from absolute elapsed time can't drift or run out, ever. */
  will-change: transform;
}

.logo-item {
  height: 40px;
  width: auto;
  flex-shrink: 0;
  /* Forces any logo — any source color — to solid white, so a mixed set of
     brand-colored SVGs/PNGs still reads as one consistent white logo strip. */
  filter: brightness(0) invert(1);
  opacity: 0.55;
  transition: opacity 0.3s ease;
}

.logo-item:hover {
  opacity: 1;
}

.logo-link {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  text-decoration: none;
  cursor: pointer;
}

@media (max-width: 768px) {
  .tools-section { padding: 64px 0 96px; }
  .tools-list { gap: 20px 28px; }
  .logos-track { gap: 40px; }
  .logo-item { height: 30px; }
}

/* MODAL */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(4, 5, 7, 0.93);
  backdrop-filter: blur(20px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.modal-backdrop.open {
  opacity: 1;
  pointer-events: all;
}

.modal-inner {
  background: #0e1018;
  border: 1px solid var(--border);
  border-radius: 16px;
  max-width: 1040px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  position: relative;
  transform: scale(0.94) translateY(12px);
  transition: transform 0.4s var(--ease);
}

.modal-backdrop.open .modal-inner {
  transform: scale(1) translateY(0);
}

.modal-close {
  position: absolute;
  top: 22px;
  right: 24px;
  z-index: 20;
  background: transparent;
  border: none;
  color: var(--text-primary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  font-weight: 300;
  line-height: 1;
  opacity: 0.75;
  text-shadow: 0 2px 10px rgba(0,0,0,0.7);
  transition: opacity 0.2s ease, transform 0.3s var(--ease);
}

.modal-close:hover {
  opacity: 1;
  transform: rotate(90deg);
}

.modal-media {
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: 16px 16px 0 0;
  overflow: hidden;
}

.modal-media img, .modal-media iframe {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border: none;
}

.modal-body {
  padding: 44px;
}

/* ADMIN PANEL */
.admin-inner {
  max-width: 640px;
}

.admin-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 28px 0 28px;
  border-bottom: 1px solid var(--border);
}

.admin-tab {
  background: transparent;
  border: none;
  color: var(--text-faint);
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 10px 14px;
  cursor: pointer;
  white-space: nowrap;
  position: relative;
  transition: color 0.2s ease;
}

.admin-tab::after {
  content: '';
  position: absolute;
  left: 14px;
  right: calc(100% - 14px);
  bottom: -1px;
  height: 2px;
  background: var(--accent);
  transition: right 0.3s var(--ease);
}

.admin-tab:hover {
  color: var(--text-secondary);
}

.admin-tab.active {
  color: var(--text-primary);
}

.admin-tab.active::after {
  right: 14px;
}

.admin-panel-hint {
  font-size: 0.85rem;
  color: var(--text-secondary);
  margin-bottom: 20px;
  line-height: 1.6;
}

.admin-group-heading {
  font-size: 0.78rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--accent);
  margin: 28px 0 14px;
}

.admin-group-heading:first-child {
  margin-top: 0;
}

.login-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.login-card {
  background: #0e1018;
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 44px;
  width: 100%;
  max-width: 380px;
}

/* Custom file-input UI — replaces the raw browser "Choose File" control
   everywhere a file input appears in the admin (hero photo, project cover). */
.file-input-wrap {
  display: flex;
  align-items: center;
  gap: 12px;
}

.file-input-name {
  font-size: 0.8rem;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 220px;
}

.field-label {
  display: block;
  font-size: 0.77rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-secondary);
  font-weight: 700;
  margin-bottom: 8px;
}

.field-input {
  width: 100%;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 11px 16px;
  border-radius: 100px;
  outline: none;
  transition: border-color 0.2s ease;
  margin-bottom: 18px;
}

/* Native <select> dropdown popups render their own opaque background,
   ignoring .field-input's translucent one — without this, the still-light
   inherited text color is nearly invisible against the browser's default
   white/light popup. Applies to every <select> site-wide, not just
   .field-input ones, since the same problem hits any unstyled select. */
select,
select option {
  background: #0e1018;
  color: var(--text-primary);
}

.field-input:focus {
  border-color: var(--border-hover);
}

textarea.field-input {
  border-radius: 14px;
}

/* CONTACT FORM — in the footer */
.contact-form {
  width: 100%;
  max-width: 560px;
  text-align: left;
}

.contact-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

@media (max-width: 560px) {
  .contact-row { grid-template-columns: 1fr; }
}

/* FORM SUBMIT — bold text row, no box */
.form-submit {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: transparent;
  border: none;
  border-top: 1px solid var(--border);
  color: var(--text-primary);
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  padding: 22px 0 4px;
  cursor: pointer;
  transition: opacity 0.2s ease, gap 0.2s ease;
  gap: 10px;
}

.form-submit:hover {
  opacity: 0.7;
  gap: 18px;
}

.form-submit .arrow {
  color: var(--accent);
  font-family: var(--font-body);
}

/* Honeypot — off-screen, not display:none (some bots skip hidden fields
   but still fill anything positioned normally), real visitors never see it. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.contact-status {
  min-height: 1.2em;
  margin: 10px 0 0;
  font-size: 0.85rem;
}

.contact-status.success { color: var(--accent); }
.contact-status.error { color: #ff6b6b; }

/* FOOTER */
.site-footer {
  border-top: 1px solid var(--border);
  padding: 72px 0 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 28px;
}

.footer-heading {
  font-family: var(--font-display);
  font-size: clamp(1.8rem, 4vw, 3.4rem);
  font-weight: 900;
  text-transform: uppercase;
  line-height: 1.0;
  letter-spacing: -0.03em;
  margin-bottom: 10px;
}

.footer-links {
  display: flex;
  justify-content: center;
  gap: 28px;
  flex-wrap: wrap;
}

.footer-links a {
  color: var(--text-secondary);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 600;
  position: relative;
  transition: color 0.25s ease;
}

.footer-links a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -3px;
  height: 1px;
  background: currentColor;
  transition: right 0.3s var(--ease);
}

.footer-links a:hover {
  color: var(--text-primary);
}

.footer-links a:hover::after {
  right: 0;
}

/* RESPONSIVE */
@media (max-width: 1024px) {
  .showcase { grid-template-columns: repeat(2, 1fr); }
  .hero { flex-direction: column-reverse; gap: 36px; }
  .hero-copy { width: 100%; }
  .hero-photo { width: 220px; align-self: flex-end; }
}

@media (max-width: 768px) {
  :root { --page-pad: 20px; }
  /* Not sticky on mobile: with the nav wrapped onto 2-3 rows below, a
     pinned header would permanently cover a large chunk of every screen
     while scrolling — it scrolls away like normal content instead. */
  .site-header { position: static; padding: 20px var(--page-pad); flex-direction: column; align-items: center; gap: 12px; }
  .brand { align-items: center; text-align: center; }
  .nav-right { flex-wrap: wrap; justify-content: center; width: 100%; row-gap: 10px; column-gap: 20px; }
  .nav-right .pill { font-size: 0.72rem; }
  .hero { padding: 20px var(--page-pad) 60px; }
  .hero-title { font-size: clamp(1.5rem, 7.6vw, 2.3rem); }
  .hero-photo { align-self: center; }
  .marquee-wrap { margin: 24px -30px 48px; }
  .project-top { flex-wrap: wrap; }
  .showcase { grid-template-columns: repeat(2, 1fr); }
  /* Same 3:4 ratio as desktop, not a forced square — a mismatched crop was
     part of what made the mobile grid look off compared to the real site. */
  .media-title-overlay { padding: 16px 18px; }
  .details-title { font-size: clamp(1.3rem, 6vw, 1.8rem); }

  /* Fixed-height embeds (Juxtapose before/after imports from Behance,
     flagged with .fixed-height-embed in blocks-render.js) render at their
     own natural size regardless of how tall a box we give them — the
     1400px scraped from Behance's desktop markup was never their real
     rendered height at any width, it just wasn't obvious until a narrow
     mobile width made the leftover empty space this dramatic. max-height
     (not height — it can't be overridden by the inline height, and doesn't
     need to) caps it without touching genuine video embeds, which always
     carry a real aspect-ratio instead. */
  .block-video.fixed-height-embed { max-height: 480px; }

  /* Filter tabs — the desktop ghost-text-tab + centered-wrap treatment
     only works for a couple of short items; it doesn't scale, and never
     will no matter how small the font gets once there are many disciplines/
     niches. Mobile gets a genuinely different pattern instead: a single-line,
     horizontally scrollable row of solid chips — the standard mobile filter-
     bar pattern (category bars, app tab strips) specifically because it
     scales to any number of options without ever wrapping. */
  .filter-section { padding: 16px 0 40px; }
  .filter-group { justify-content: flex-start; }
  .filter-tabs-row {
    flex-wrap: nowrap;
    justify-content: flex-start;
    gap: 8px;
    margin: 0 calc(var(--page-pad) * -1);
    padding: 4px var(--page-pad) 10px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Fades the row's trailing edge so a cut-off chip visibly hints
       "more to scroll" instead of looking like the list just ends. */
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent 100%);
  }
  .filter-tabs-row::-webkit-scrollbar { display: none; }
  .disc-sep, .niche-sep { display: none; }
  .disc-btn, .niche-btn {
    flex: 0 0 auto;
    font-family: var(--font-body);
    letter-spacing: 0.02em;
    border-radius: 999px;
    border: 1px solid var(--border);
    white-space: nowrap;
  }
  .disc-btn::after, .niche-btn::after { display: none; }
  .disc-btn {
    font-size: 0.82rem;
    font-weight: 800;
    text-transform: uppercase;
    background: rgba(255, 255, 255, 0.06);
    padding: 9px 16px;
  }
  .niche-btn {
    font-size: 0.72rem;
    font-weight: 600;
    background: transparent;
    padding: 7px 14px;
  }
  .disc-btn.active, .niche-btn.active {
    background: var(--text-primary);
    color: var(--bg);
    border-color: var(--text-primary);
  }
}

/* Project tile titles are hover-only by design on desktop (mouse-driven
   reveal) — but touch devices have no real hover state, which made every
   project's title/client/year invisible on mobile, not just restyled.
   `hover: none` targets actual touch capability (not just narrow screens,
   so a touch tablet at wide viewport still gets this), always showing the
   overlay and adding a scrim so white text stays readable over any thumbnail. */
@media (hover: none) {
  .media-title-overlay {
    background: linear-gradient(to top, rgba(0,0,0,0.7), rgba(0,0,0,0) 55%);
  }
  .overlay-title, .overlay-sub {
    opacity: 1;
    transform: none;
  }
}

/* At small (phone-width) touch tiles, the desktop hover-reveal's title size
   is too large to sit permanently on-screen — a 2-column 1:1 tile is only
   ~160px tall, and a 3-line title at that size crowds out the whole tile.
   Shrink and tighten it specifically for this case, not for wider touch
   devices (a touch tablet at 1024px still gets the roomier desktop sizing). */
@media (hover: none) and (max-width: 768px) {
  .media-title-overlay { padding: 10px 12px; }
  .overlay-title { font-size: 0.78rem; -webkit-line-clamp: 2; }
  .overlay-sub { font-size: 0.6rem; margin-top: 3px; }
}

/* PROJECT PAGE — dedicated case-study page, Behance-style: full-bleed stacked media, no crop/borders */
.project-page-header {
  max-width: 1400px;
  margin: 0 auto;
  padding: 64px var(--page-pad) 56px;
}

.project-meta-label {
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--accent);
  margin-bottom: 14px;
}

.project-page-title {
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 5vw, 4rem);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin-bottom: 20px;
}

.project-client-line {
  color: var(--text-faint);
  font-size: 0.95rem;
}

/* Blocks stack full-bleed, edge to edge, no gap — matches Behance's canvas */
.project-blocks {
  display: flex;
  flex-direction: column;
  max-width: 1400px;
  margin: 0 auto;
  padding-bottom: 120px;
}

.block-image picture {
  display: block;
}

.block-image img {
  width: 100%;
  display: block;
}

.block-image .block-caption {
  padding: 16px var(--page-pad);
  color: var(--text-faint);
  font-size: 0.85rem;
  text-align: center;
}

/* Full-bleed color panel — the background spans edge to edge (usable as a layer
   between images, like a Behance divider panel); the text column stays readable-width */
.block-text-panel {
  width: 100%;
}

.block-text {
  max-width: 820px;
  margin: 0 auto;
  padding: 64px var(--page-pad);
  font-size: 1.1rem;
  line-height: 1.85;
  color: var(--text-secondary);
}

.block-text p {
  margin-bottom: 1.2em;
}

.block-text p:last-child {
  margin-bottom: 0;
}

.block-text a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.block-text h1, .block-text h2, .block-text h3 {
  font-family: var(--font-display);
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0.6em 0 0.4em;
}

/* Quill output classes — rendered identically on the public page (Quill itself isn't loaded here).
   Font size is now a style-based Quill attributor (inline font-size), so no ql-size-* classes are
   emitted for new content — the rules below remain only for any older saved content that used them. */
.block-text .ql-size-small { font-size: 0.75em; }
.block-text .ql-size-large { font-size: 1.5em; }
.block-text .ql-size-huge { font-size: 2.2em; }
.block-text .ql-font-jakarta { font-family: 'Plus Jakarta Sans', sans-serif; }
.block-text .ql-font-syne { font-family: 'Syne', sans-serif; }
.block-text .ql-font-inter { font-family: 'Inter', sans-serif; }
.block-text .ql-font-poppins { font-family: 'Poppins', sans-serif; }
.block-text .ql-font-montserrat { font-family: 'Montserrat', sans-serif; }
.block-text .ql-font-playfair { font-family: 'Playfair Display', serif; }
.block-text .ql-font-oswald { font-family: 'Oswald', sans-serif; }
.block-text .ql-font-robotoslab { font-family: 'Roboto Slab', serif; }
.block-text .ql-font-spacegrotesk { font-family: 'Space Grotesk', sans-serif; }
.block-text .ql-font-bebasneue { font-family: 'Bebas Neue', sans-serif; }
.block-text .ql-font-worksans { font-family: 'Work Sans', sans-serif; }
.block-text .ql-font-dmsans { font-family: 'DM Sans', sans-serif; }
.block-text .ql-align-center { text-align: center; }
.block-text .ql-align-right { text-align: right; }
.block-text .ql-align-justify { text-align: justify; }

/* Photo grid — justified rows computed in JS: each image keeps its own aspect
   ratio, rows are scaled to fill the full width. Containment is intentional:
   if stored dimensions differ slightly from the file’s real dimensions, the
   complete image is still shown instead of cropping its top or bottom. */
.block-photogrid {
  display: flex;
  flex-direction: column;
}

.photogrid-row {
  display: flex;
}

.photogrid-row picture {
  display: block;
  overflow: hidden;
}

.photogrid-row img {
  display: block;
  object-fit: contain;
  object-position: center;
  background: var(--bg);
}

.lightbox-trigger {
  cursor: zoom-in;
}

/* LIGHTBOX */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(4, 5, 7, 0.96);
  backdrop-filter: blur(12px);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.lightbox.open {
  opacity: 1;
  pointer-events: all;
}

.lightbox-img {
  max-width: 90vw;
  max-height: 90vh;
  object-fit: contain;
  display: block;
}

.lightbox-close {
  position: absolute;
  top: 28px;
  right: 32px;
  background: transparent;
  border: none;
  color: var(--text-primary);
  font-size: 1.6rem;
  cursor: pointer;
  opacity: 0.75;
  transition: opacity 0.2s ease, transform 0.3s var(--ease);
}

.lightbox-close:hover {
  opacity: 1;
  transform: rotate(90deg);
}

.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--border);
  color: var(--text-primary);
  width: 48px;
  height: 48px;
  border-radius: 50%;
  cursor: pointer;
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
}

.lightbox-nav:hover {
  background: rgba(255,255,255,0.12);
  border-color: var(--border-hover);
}

.lightbox-prev { left: 24px; }
.lightbox-next { right: 24px; }

@media (max-width: 640px) {
  .lightbox-nav { width: 40px; height: 40px; font-size: 1rem; }
  .lightbox-prev { left: 10px; }
  .lightbox-next { right: 10px; }
}

.block-video {
  aspect-ratio: 16 / 9;
  background: #000;
}

.block-video iframe {
  width: 100%;
  height: 100%;
  border: none;
  display: block;
}

/* Before/after compare block — a native equivalent of the Juxtapose widget.
   .compare-after is a normal block-level <img> that sets the container's
   height; .compare-before sits absolutely on top of it, clipped via
   clip-path (not resized), so it never visually scales as the reveal
   amount changes — only .compare-before's clip-path and .compare-handle's
   left offset are ever touched at runtime (compare-slider.js). */
.block-compare {
  position: relative;
  width: 100%;
  overflow: hidden;
  user-select: none;
  cursor: ew-resize;
  line-height: 0;
  /* pan-y (not none): lets a vertical drag over the slider scroll the page
     natively, same as everywhere else on the page — only a horizontal drag
     is claimed for the slider itself. Without this, touching the image at
     all blocked scrolling, forcing a finger onto a pixel outside the image
     just to keep reading the page (reported directly by the admin). */
  touch-action: pan-y;
}
.compare-img {
  display: block;
  width: 100%;
  /* Grabbing an <img> starts the browser's own native "drag this image out"
     gesture unless explicitly disabled, which swallows the pointermove
     events the slider needs — the only spot that reliably worked before
     this fix was the handle div itself, since it isn't an <img>. */
  -webkit-user-drag: none;
  user-drag: none;
  -webkit-touch-callout: none;
}
.compare-after { position: relative; }
.compare-before {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  object-fit: cover;
}
.compare-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background: rgba(255, 255, 255, 0.9);
  transform: translateX(-50%);
  pointer-events: none;
}
.compare-handle::after {
  content: '\2194';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #fff;
  color: #0e1018;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
}
.compare-label {
  position: absolute;
  top: 14px;
  padding: 5px 12px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  border-radius: 4px;
  pointer-events: none;
}
.compare-label-before { left: 14px; }
.compare-label-after { right: 14px; }

/* Custom Code / Embed Code blocks — the iframe itself is sized inline
   (custom-code-render.js sets height from the block's own field); this
   just gives the wrapper a sane baseline while it's empty/loading. */
.block-customcode, .block-embedcode {
  min-height: 60px;
}

/* Fixed-width custom designs keep their full canvas on narrow screens. The
   renderer scales the sandbox proportionally so the complete design fits the
   available width without stretching or cropping. */
.block-customcode.custom-code-wide {
  position: relative;
  width: 100%;
  max-width: 100%;
  overflow: hidden;
}

.block-customcode.custom-code-wide > iframe {
  display: block;
  max-width: none;
  transform-origin: top left;
}

/* Self-hosted video block (uploaded, not an embed) — same full-bleed treatment as an image */
.block-video-native video {
  width: 100%;
  display: block;
  background: #000;
  cursor: pointer;
}

/* Video grid — same justified-row engine as the photo grid, capped at 3/row */
.block-videogrid {
  display: flex;
  flex-direction: column;
}

/* Grid videos get their inline height set directly by video-player.js (matching
   the justified-row layout math); standalone video blocks intentionally get none,
   so they fall back to this width-only rule and keep their natural aspect ratio. */
.uploaded-video {
  display: block;
  width: 100%;
  object-fit: cover;
  background: #000;
  cursor: pointer;
}

/* Play-icon overlay + hover-preview wrapper (injected around every .uploaded-video
   by video-player.js) — the icon fades out once the video starts playing, giving
   a clear "this is a video" signal even before anyone hovers or clicks. */
.video-thumb {
  position: relative;
  display: block;
  overflow: hidden;
}

.video-thumb iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Public project/blog video cards. Every provider uses the same visual card;
   the actual player is created only inside the preview overlay after a click. */
.video-card {
  position: relative;
  display: block;
  overflow: hidden;
  padding: 0;
  border: 0;
  background: #050505;
  color: #fff;
  font: inherit;
  line-height: 0;
  text-align: left;
  cursor: pointer;
}

.video-card-thumbnail,
.video-card-placeholder-label {
  display: block;
  width: 100%;
  height: 100%;
}

.video-card-thumbnail { object-fit: cover; }
.video-card-placeholder-label {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  color: rgba(255,255,255,.62);
  font-size: .68rem;
  letter-spacing: .08em;
  line-height: 1.3;
  text-align: center;
  text-transform: uppercase;
}

.video-card-shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 48%, rgba(0,0,0,.42));
  pointer-events: none;
}

.video-card-play {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  width: 48px;
  height: 48px;
  place-items: center;
  border-radius: 50%;
  background: rgba(0,0,0,.62);
  color: #fff;
  line-height: 1;
  transform: translate(-50%, -50%);
  transition: transform .2s var(--ease), background .2s var(--ease);
}

.video-card-play svg { display: block; }
.video-card:hover .video-card-play,
.video-card:focus-visible .video-card-play {
  background: var(--accent);
  transform: translate(-50%, -50%) scale(1.08);
}
.video-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.video-card-error {
  display: grid;
  place-items: center;
  padding: 18px;
  color: var(--text-faint);
  font-size: .75rem;
  line-height: 1.4;
  text-align: center;
}

.embed-error,
.grid-embed-error {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 120px;
  padding: 24px;
  background: #111;
  color: var(--text-faint);
  text-align: center;
  font-size: 0.82rem;
}

.grid-embed-error {
  height: 100%;
  min-height: 0;
}

.video-embed-help {
  flex-basis: 100%;
  color: var(--text-faint);
  font-size: 0.74rem;
  line-height: 1.45;
}

.video-play-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  padding-left: 3px; /* optically center the triangle */
  opacity: 1;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.video-thumb:hover .video-play-icon {
  transform: translate(-50%, -50%) scale(1.08);
}

.video-thumb.is-playing .video-play-icon {
  opacity: 0;
}

/* Once native controls take over (first click), our custom icon steps aside
   permanently — the native control bar's own play button owns that job now. */
.video-thumb.native-controls-active .video-play-icon {
  display: none;
}

/* VIDEO EXPAND OVERLAY — caps at the video's native resolution, never upscales */
.video-expand-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(4, 5, 7, 0.96);
  backdrop-filter: blur(12px);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.video-expand-overlay.open {
  opacity: 1;
  pointer-events: all;
}

.video-preview-open { overflow: hidden; }

.video-expand-player,
.video-expand-frame {
  display: none;
  max-width: calc(100vw - 96px);
  max-height: calc(100vh - 96px);
  background: #000;
}

.video-expand-frame { border: 0; }

.video-expand-close {
  position: absolute;
  top: 28px;
  right: 32px;
  background: transparent;
  border: none;
  color: var(--text-primary);
  font-size: 1.6rem;
  cursor: pointer;
  opacity: 0.75;
  transition: opacity 0.2s ease, transform 0.3s var(--ease);
}

.video-expand-close:hover {
  opacity: 1;
  transform: rotate(90deg);
}

.project-not-found {
  padding: 160px var(--page-pad);
  text-align: center;
  color: var(--text-faint);
}

/* REDUCED MOTION */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .cursor { display: none; }
}


/* INFORMATION SECTIONS — reusable About Statement and Capabilities layouts */
.info-section {
  max-width: 1760px;
  margin: 0 auto;
  padding-top: 118px;
  padding-bottom: 118px;
  border-top: 1px solid var(--border);
}
.info-section-index {
  display: flex;
  align-items: center;
  gap: 18px;
  color: var(--accent);
}
.info-section-index::before {
  content: '00';
  color: var(--accent);
}
.info-section-index span { color: var(--text-secondary); }
.info-about-grid,
.info-capabilities-grid {
  display: grid;
  grid-template-columns: minmax(170px, .72fr) 1.7fr;
  gap: 9vw;
  margin-top: 72px;
}
.info-kicker {
  max-width: 220px;
  color: var(--text-secondary);
  font: .68rem/1.65 'DM Mono', monospace;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.info-about-copy { max-width: 840px; }
.info-about-copy h2,
.info-capabilities-intro h2 {
  max-width: 820px;
  margin: 0 0 30px;
  color: var(--text-primary);
  font-family: var(--font-display);
  font-size: clamp(3.2rem, 7vw, 7.5rem);
  letter-spacing: -.09em;
  line-height: .88;
}
.info-about-copy p,
.info-capability-description p {
  max-width: 620px;
  margin: 0 0 18px;
  color: var(--text-secondary);
  font-size: .96rem;
  line-height: 1.75;
}
.info-inline-link {
  color: var(--accent);
  border-bottom: 1px solid currentColor;
  transition: opacity .2s var(--ease);
}
.info-inline-link:hover { opacity: .7; }
.info-button {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  margin-top: 16px;
}
.info-button .arrow { transition: transform .2s var(--ease); }
.info-button:hover .arrow { transform: translate(3px, -3px); }
.info-stats-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
  margin-top: 92px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
}
.info-stats-row div { display: grid; gap: 10px; }
.info-stats-row strong {
  color: var(--accent);
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 5.2vw, 5.8rem);
  letter-spacing: -.09em;
  line-height: .8;
}
.info-stats-row span {
  color: var(--text-secondary);
  font: .62rem 'DM Mono', monospace;
  text-transform: uppercase;
}
.info-capabilities-intro h2 { max-width: 430px; }
.info-capability-list { border-top: 1px solid var(--border); }
.info-capability-row {
  display: grid;
  grid-template-columns: 48px minmax(145px, .92fr) 1.35fr;
  gap: 24px;
  align-items: start;
  padding: 27px 0;
  border-bottom: 1px solid var(--border);
  transition: padding .25s var(--ease), background .25s var(--ease);
}
.info-capability-row:hover {
  padding-left: 14px;
  padding-right: 14px;
  background: rgba(255,255,255,.025);
}
.info-capability-number { color: var(--accent); padding-top: 3px; }
.info-capability-title h3 {
  margin: 0;
  color: var(--text-primary);
  font-size: 1.1rem;
  letter-spacing: -.04em;
}
.info-capability-title .info-button {
  margin-top: 12px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--accent);
  font: .62rem 'DM Mono', monospace;
  text-transform: uppercase;
}
.info-capability-description p { margin: 0; font-size: .84rem; line-height: 1.65; }
.info-capability-cta { padding-top: 24px; }
@media (max-width: 760px) {
  .info-section { padding-top: 84px; padding-bottom: 84px; }
  .info-about-grid,
  .info-capabilities-grid { grid-template-columns: 1fr; gap: 44px; margin-top: 52px; }
  .info-kicker { max-width: 330px; }
  .info-about-copy h2,
  .info-capabilities-intro h2 { font-size: clamp(3.2rem, 14vw, 6rem); }
  .info-stats-row { margin-top: 62px; gap: 14px; }
  .info-stats-row strong { font-size: 2.5rem; }
  .info-stats-row span { font-size: .51rem; line-height: 1.45; }
  .info-capability-row { grid-template-columns: 34px 1fr; gap: 12px; }
  .info-capability-description { grid-column: 2; }
}


/* Compression Panels section template */
.compression-category-section { width:100%; padding:72px 0; background:var(--bg); color:var(--text-primary); }
.compression-category-heading { display:flex; justify-content:space-between; padding:0 4vw 18px; color:var(--text-secondary); font-size:.62rem; letter-spacing:.14em; text-transform:uppercase; }
.compression-category-track { display:flex; width:100%; min-height:520px; overflow:hidden; background:#1a1a1a; }
.compression-category-panel { flex:1; position:relative; min-width:0; overflow:hidden; cursor:pointer; border-right:1px solid #111; transition:flex .8s cubic-bezier(.77,0,.175,1); }
.compression-category-track:hover > .compression-category-panel { flex:1; }
.compression-category-track > .compression-category-panel:hover { flex:6; }
.compression-category-bg { position:absolute; inset:0; overflow:hidden; background:#2c2c2c; }
.compression-category-bg img { width:100%; height:100%; object-fit:cover; filter:brightness(.4) grayscale(100%); transform:scale(1.05); transition:filter .8s cubic-bezier(.77,0,.175,1), transform .8s cubic-bezier(.77,0,.175,1); }
.compression-category-panel:hover .compression-category-bg img { filter:brightness(.85) grayscale(0); transform:scale(1); }
.compression-category-bg::after { content:''; position:absolute; inset:0; background:linear-gradient(180deg,rgba(26,26,26,.5),transparent 35%,rgba(26,26,26,.75)); }
.compression-category-index { position:absolute; top:28px; left:50%; z-index:2; transform:translateX(-50%); color:#f0f0f0; opacity:.4; white-space:nowrap; font-size:.6rem; }
.compression-category-spine { position:absolute; bottom:36px; left:50%; z-index:2; transform:translateX(-50%) rotate(180deg); writing-mode:vertical-rl; color:#f0f0f0; font-family:var(--font-display); font-size:clamp(1.5rem,3.2vw,3.2rem); line-height:1; text-transform:uppercase; white-space:nowrap; transition:opacity .4s cubic-bezier(.77,0,.175,1), transform .4s cubic-bezier(.77,0,.175,1); }
.compression-category-panel:hover .compression-category-spine { opacity:.18; transform:translateX(-50%) rotate(180deg) translateY(-18px); }
.compression-category-details { position:absolute; right:34px; bottom:34px; left:34px; z-index:3; opacity:0; transform:translateX(-24px); pointer-events:none; transition:opacity .5s cubic-bezier(.77,0,.175,1) .12s, transform .5s cubic-bezier(.77,0,.175,1) .12s; }
.compression-category-panel:hover .compression-category-details { opacity:1; transform:translateX(0); pointer-events:auto; }
.compression-category-label { margin:0 0 10px; color:#dfff00; font-size:.62rem; letter-spacing:.18em; text-transform:uppercase; }
.compression-category-details h4 { max-width:560px; margin:0 0 16px; color:#f0f0f0; font-family:var(--font-display); font-size:clamp(1.8rem,4vw,3.5rem); line-height:.95; text-transform:uppercase; }
.compression-category-meta { display:flex; gap:24px; margin-bottom:22px; color:rgba(240,240,240,.7); font-size:.64rem; text-transform:uppercase; }
.compression-category-details .pill { background:#dfff00; color:#1a1a1a; }
@media (max-width:760px) {
  .compression-category-section { padding:56px 0; }
  .compression-category-track { flex-direction:column; min-height:0; }
  .compression-category-track:hover > .compression-category-panel, .compression-category-track > .compression-category-panel:hover { flex:none; }
  .compression-category-panel { flex:none; height:68vh; border-right:0; border-bottom:1px solid #111; }
  .compression-category-spine { display:none; }
  .compression-category-details { right:24px; bottom:28px; left:24px; opacity:1; transform:none; pointer-events:auto; }
  .compression-category-bg img { filter:brightness(.6) grayscale(0); transform:none; }
}


/* Project-display templates span the full showcase grid instead of occupying one tile. */
.showcase > .compression-category-section,
.gallery-section > .compression-category-section { grid-column: 1 / -1; width: 100%; }
.compression-category-section { min-height: min(860px, calc(100vh - 150px)); padding: clamp(28px, 4vw, 72px) 0; }
.compression-category-track { min-height: clamp(520px, calc(100vh - 270px), 760px); }
.featured-compression-section,
.allprojects-compression-section,
.category-compression-section,
.custom-selection-compression-section { width: 100%; }
@media (max-width: 760px) {
  .compression-category-section { min-height: 0; }
  .compression-category-track { min-height: 0; }
}


/* Compression Panels theme inheritance: the layout keeps its structure, but all visual tokens come from the active site theme. */
.compression-category-section {
  background: var(--bg);
  color: var(--text-primary);
  font-family: var(--font-body);
}
.compression-category-track { background: var(--bg); }
.compression-category-panel { border-right-color: var(--border); }
.compression-category-bg { background: var(--bg); }
.compression-category-bg::after {
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg), transparent 28%), transparent 35%, color-mix(in srgb, var(--bg), transparent 12%));
}
.compression-category-heading .mono,
.compression-category-index,
.compression-category-label,
.compression-category-meta,
.compression-category-section .mono {
  font-family: var(--font-body);
}
.compression-category-heading .mono { color: var(--text-secondary); }
.compression-category-index { color: var(--text-primary); }
.compression-category-spine,
.compression-category-details h4 {
  color: var(--text-primary);
  font-family: var(--font-display);
  font-weight: 900;
}
.compression-category-label { color: var(--accent); }
.compression-category-meta { color: var(--text-secondary); }
.compression-category-details .pill,
.compression-category-details .pill.primary {
  background: var(--accent);
  color: var(--bg);
  font-family: var(--font-body);
}
.compression-category-details .pill.primary::after { background: var(--bg); }
@media (max-width: 760px) {
  .compression-category-panel { border-bottom-color: var(--border); }
}
