/* Shahzaib Portfolio — v12 — 30 Aug 2026 */
/* =========================================================================
   portfolio-fixes.css   —   loaded AFTER portfolio.css
   Every correction lives here so the eventual rebuild of portfolio.css is
   a matter of folding this in and deleting the file.
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. STACKING ORDER
   .header was z-index 50000 while .modal was 2000, so the fixed header
   painted over every dialog and clipped the media and its close button.
------------------------------------------------------------------------- */
.modal,
.fullViewer { z-index: 60000 !important; }

body.scrollLocked .header,
body.scrollLocked .floatingActions,
body.scrollLocked .backTop,
body.scrollLocked .drawer,
body.scrollLocked #network,
body.scrollLocked .cursor,
body.scrollLocked .cursorGlow { display: none !important; }

body.scrollLocked { overflow: hidden !important; }

/* -------------------------------------------------------------------------
   2. CAROUSEL
   A three-slide window on a flex track. The track sits at -100% and the
   drag moves it with the finger, so the gesture is continuous rather than
   a snap-back followed by a cross-fade.
------------------------------------------------------------------------- */
.pfCarousel {
  position: relative;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  border-radius: inherit;
  overflow: hidden;
  background: #05090f;
}

.pfViewport {
  position: absolute;
  inset: 0;
  overflow: hidden;
  touch-action: pan-y;          /* vertical scrolling stays with the page */
  border-radius: inherit;
}

.pfTrack {
  display: flex;
  width: 100%;
  height: 100%;
  will-change: transform;
  transform: translate3d(-100%, 0, 0);
  backface-visibility: hidden;
}

.pfSlide {
  position: relative;
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  min-width: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
}

.pfSlide img.pfImage,
.pfSlide video.pfVideo {
  position: relative !important;
  z-index: 1 !important;
  display: block !important;
  max-width: 100% !important;
  max-height: 100% !important;
  width: auto !important;
  height: auto !important;
  object-fit: contain !important;
  border-radius: 0 !important;
}

/* Media sits on a plain dark surface. An earlier version filled the empty
   bands with a blurred, scaled-up copy of the same photo; that enlarged
   copy is what read as "zoomed". The image is now simply shown whole. */
.pfCarousel { background: #05090f; }
.pfSlide { background: transparent; }

.pfSlideFailed { background: linear-gradient(135deg, #0c141e, #080e16); }
.pfSlideFailed .pfImage { opacity: 0; }
.pfSlideFailed::after {
  content: 'Media unavailable';
  position: absolute;
  z-index: 2;
  color: rgba(255, 255, 255, .45);
  font-size: 12px;
  letter-spacing: .06em;
}

.projectMediaEmpty { display: none !important; }

/* ---- video signposting on cards ------------------------------------------
   A visitor swiping the home page must be able to tell a video from a
   still without opening it.
------------------------------------------------------------------------- */
.pfPlay {
  position: absolute;
  z-index: 3;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 58px;
  height: 58px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(4, 10, 17, .62);
  border: 1.5px solid rgba(98, 232, 255, .75);
  backdrop-filter: blur(3px);
  box-shadow: 0 6px 26px rgba(0, 0, 0, .45);
  pointer-events: none;
}
.pfPlay svg { width: 26px; height: 26px; fill: #fff; }

.pfKind {
  position: absolute;
  z-index: 3;
  top: 10px;
  left: 10px;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(4, 10, 17, .78);
  border: 1px solid rgba(98, 232, 255, .45);
  color: #cfeeff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  pointer-events: none;
}

/* ---- arrows ------------------------------------------------------------- */
.pfNav {
  position: absolute;
  z-index: 6;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(88, 166, 255, .34);
  background: rgba(4, 10, 17, .62);
  color: #fff;
  cursor: pointer;
  transition: background .2s ease, border-color .2s ease, opacity .2s ease;
}
.pfNav svg {
  width: 22px; height: 22px; fill: none; stroke: currentColor;
  stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
.pfNav:hover { background: rgba(6, 16, 26, .9); border-color: var(--blue, #58a6ff); }
.pfNav--prev { left: 8px; }
.pfNav--next { right: 8px; }

/* The arrows stay on the centre line. The browser's own transport controls
   sit near the middle third horizontally, so pinned to the extreme edges
   they never collide with the skip buttons. */
/* ---- dots and counter --------------------------------------------------- */
.pfBar {
  position: absolute;
  z-index: 5;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  pointer-events: none;
  background: linear-gradient(180deg, transparent, rgba(3, 8, 14, .68));
}

.pfDots { display: flex; align-items: center; gap: 5px; min-width: 0; flex-wrap: nowrap; overflow: hidden; }
.pfDots span {
  flex: 0 0 auto;
  width: 4px; height: 4px; border-radius: 50%;
  background: rgba(255, 255, 255, .42);
  transition: width .2s ease, background .2s ease;
}
.pfDots span.active { width: 15px; height: 3px; border-radius: 999px; background: #59d9ff; }

/* A project with a lot of media would otherwise grow an unreadable dot
   row; past 12 items the counter carries the information on its own. */
.pfCarousel[data-count="13"] .pfDots,
.pfCarousel[data-count="14"] .pfDots,
.pfCarousel[data-count="15"] .pfDots,
.pfCarousel[data-count="16"] .pfDots,
.pfCarousel[data-count="17"] .pfDots,
.pfCarousel[data-count="18"] .pfDots,
.pfCarousel[data-count="19"] .pfDots,
.pfCarousel[data-count="20"] .pfDots { display: none; }

.pfCount {
  flex: 0 0 auto;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgba(3, 9, 15, .7);
  border: 1px solid rgba(88, 166, 255, .28);
  color: rgba(255, 255, 255, .86);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
}

/* No expand button any more. A video already carries the browser's own
   full-screen control, and a second square button beside it was redundant.
   Stills open full screen when tapped instead.
------------------------------------------------------------------------- */
.pfCarousel[data-kind="image"] .pfViewport { cursor: zoom-in; }

/* Inside the lightbox and the project page viewer there is no expand
   button, so the bar can sit lower. */
#mediaLightbox .pfBar,
#fullViewer .pfBar { padding-bottom: max(10px, env(safe-area-inset-bottom)); }

/* -------------------------------------------------------------------------
   3. CAROUSEL HOSTS
   Explicit heights per context; svh so mobile browser chrome is accounted
   for. Without these the flex track has no height to fill.
------------------------------------------------------------------------- */
.projectMedia { position: relative; overflow: hidden; }
.projectMedia > .pfCarousel { position: absolute; inset: 0; }

#modalMedia { position: relative; height: 54svh; min-height: 240px; }
/* These had no resolved height of their own, so a child at height:100%
   collapsed to zero and the full-screen view opened empty. */
#mediaLightbox .lightboxMedia {
  position: relative !important;
  width: 100% !important;
  height: 84svh !important;
  max-height: 84svh !important;
  display: block !important;
}

#projectMedia { position: relative; height: 62svh; min-height: 260px; }
#fullViewer #fullMedia {
  position: relative !important;
  width: 100% !important;
  height: 84svh !important;
  max-height: 84svh !important;
  display: block !important;
}
#mediaLightbox .lightboxMedia > .pfCarousel,
#fullViewer #fullMedia > .pfCarousel { height: 100% !important; }

@media (max-width: 560px) {
  #modalMedia { height: 46svh; min-height: 200px; }
  #mediaLightbox .lightboxMedia,
  #fullViewer #fullMedia { height: 76svh !important; max-height: 76svh !important; }
  #projectMedia { height: 52svh; min-height: 220px; }
  .pfPlay { width: 50px; height: 50px; }
  .pfPlay svg { width: 22px; height: 22px; }
}

@media (max-height: 480px) and (orientation: landscape) {
  #modalMedia { height: 62svh; }
  #projectMedia { height: 66svh; }
  #mediaLightbox .lightboxMedia,
  #fullViewer #fullMedia { height: 80svh !important; max-height: 80svh !important; }
}

/* The old fixed-size media rules fought the carousel for control. */
.modalMediaDirect,
.projectPageDirect,
.projectMediaFrame,
.homeMediaControls,
.mediaIndicators,
.mediaCounter,
.modalNav,
.projectMediaNav,
.mediaModalFull,
.projectFullscreen,
.projectVideoBadge,
.portfolioVideoControls { display: none !important; }

/* -------------------------------------------------------------------------
   4. CREATIVE — SOCIAL MEDIA
   Presented as the document it is. Wide pointer-driven screens embed the
   real PDF; phones get a page-by-page viewer of the same file, because iOS
   Safari will not render a multi-page PDF inside an iframe.
------------------------------------------------------------------------- */
.socialDoc {
  border: 1px solid rgba(88, 166, 255, .22);
  border-radius: 16px;
  background: rgba(7, 13, 21, .6);
  padding: 12px;
  overflow: hidden;
}

.socialDocBar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.socialDocTitle { font-size: 14px; font-weight: 700; color: #eaf4ff; }

.creativeDownload {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  min-height: 44px;
  border-radius: 12px;
  border: 1px solid rgba(88, 166, 255, .38);
  background: rgba(8, 16, 26, .7);
  color: #cfeeff;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.creativeDownload:hover { border-color: var(--cyan, #62e8ff); color: #fff; }

.socialDocFrame { display: none; }
.socialDocPages { position: relative; height: 72svh; min-height: 340px; border-radius: 12px; overflow: hidden; }

@media (pointer: fine) and (min-width: 900px) {
  .socialDocFrame { display: block; height: 78svh; }
  .socialDocFrame iframe {
    width: 100%; height: 100%; border: 0; border-radius: 12px; background: #fff;
  }
  .socialDocPages { display: none; }
}

/* -------------------------------------------------------------------------
   5. HEADER
   The role line wrapped onto two lines and ran under the menu button on
   narrow phones.
------------------------------------------------------------------------- */
.headRole {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: calc(100vw - 150px);
}
@media (max-width: 420px) { .headRole { max-width: calc(100vw - 130px); font-size: 8.4px !important; } }
@media (max-width: 360px) { .headRole { max-width: calc(100vw - 120px); font-size: 7.8px !important; } }

/* -------------------------------------------------------------------------
   6. FOCUS AND TOUCH TARGETS
------------------------------------------------------------------------- */
:focus-visible { outline: 2px solid #62e8ff !important; outline-offset: 3px !important; border-radius: 4px; }
.projectCard, .galleryItem { cursor: pointer; }
.projectCard:focus-visible, .galleryItem:focus-visible { outline-offset: 4px !important; }

@media (pointer: coarse) {
  .switch { min-height: 44px !important; }
  .footerLink { min-height: 44px !important; display: flex !important; align-items: center !important; }
  .loadMoreBtn { min-height: 48px !important; }
}

/* -------------------------------------------------------------------------
   7. OVERLAP GUARDS
------------------------------------------------------------------------- */
@media (max-width: 560px) { .backTop { bottom: 88px !important; right: 12px !important; } }

.modalText h2,
.projectPage .projectTitle { overflow-wrap: anywhere; hyphens: auto; }
.tags, .projectTags, .footerTags { min-width: 0; }
.tag, .footerTag { max-width: 100%; overflow-wrap: anywhere; }

@media (max-height: 480px) and (orientation: landscape) {
  .hero { min-height: auto !important; padding-top: 76px !important; padding-bottom: 40px !important; }
  .portraitArea { min-height: 210px !important; height: 42vh !important; }
  .heroStats { gap: 14px !important; }
}

@supports (padding: max(0px)) {
  .floatingActions { padding-right: max(0px, env(safe-area-inset-right)); }
  .backTop { margin-bottom: env(safe-area-inset-bottom); }
  #mediaLightbox .lightboxClose,
  #fullViewer #fullClose {
    top: max(10px, env(safe-area-inset-top)) !important;
    right: max(10px, env(safe-area-inset-right)) !important;
  }
  .footer { padding-bottom: max(20px, env(safe-area-inset-bottom)) !important; }
}

/* -------------------------------------------------------------------------
   8. REDUCED MOTION AND PRINT
------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  #network, .cursor, .cursorGlow, .cursorParticle { display: none !important; }
  .pfTrack { transition: none !important; }
}

@media print {
  #network, .cursor, .cursorGlow, .header, .drawer, .floatingActions,
  .backTop, .backPortfolio, .modal, .fullViewer,
  .pfNav, .pfBar, .pfPlay { display: none !important; }
  body { background: #fff !important; color: #000 !important; }
  .projectCard, .infoCard { break-inside: avoid; border: 1px solid #ccc !important; }
}

/* -------------------------------------------------------------------------
   9. PROJECT PAGE
   The title was printed twice: once as the page heading and again above the
   description. One is enough.
------------------------------------------------------------------------- */
#projectDetailTitle { display: none !important; }

/* -------------------------------------------------------------------------
   10. FULL-SCREEN STAGE
   The stage reserved a 64px column on each side for the old external arrow
   buttons. The carousel draws its own arrows inside the media box, so those
   columns were 128px of wasted width on a phone.
------------------------------------------------------------------------- */
#mediaLightbox .lightboxStage,
#fullViewer .fullStage {
  grid-template-columns: minmax(0, 1fr) !important;
  padding: 10px !important;
}
#mediaLightbox .lightboxMedia,
#fullViewer #fullMedia { grid-column: 1 !important; }

/* =====================================================================
   MEDIA FIT FIX — 29 Aug 2026
   Goal: every photo/video is shown completely inside its media frame.
   No cropping, zooming, stretching or hover enlargement.
   This intentionally preserves the existing desktop/mobile frame sizes.
   ===================================================================== */

/* Never enlarge/crop a project image on hover. The complete source frame
   must remain visible on desktop as well as touch devices. */
.projectCard:hover .projectMedia img,
.projectCard:focus-within .projectMedia img {
  transform: none !important;
}

/* The media itself owns the fit. Contain preserves the complete source
   aspect ratio, regardless of whether the source is landscape, portrait,
   square or video. */
.pfSlide {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  overflow: hidden !important;
}

.pfSlide img.pfImage,
.pfSlide video.pfVideo {
  display: block !important;
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
  object-fit: contain !important;
  object-position: center center !important;
  transform: none !important;
  border-radius: 0 !important;
}

/* Keep the media frame stable while allowing the complete source to fit. */
.projectMedia .pfCarousel,
#modalMedia .pfCarousel,
#projectMedia .pfCarousel,
#mediaLightbox .lightboxMedia > .pfCarousel,
#fullViewer #fullMedia > .pfCarousel {
  overflow: hidden !important;
}

/* On phones, do not let browser/touch hover states enlarge the media. */
@media (hover: none) and (pointer: coarse) {
  .projectCard:hover .projectMedia img,
  .projectCard:active .projectMedia img,
  .projectCard:focus .projectMedia img {
    transform: none !important;
  }
}



/* =========================================================================
   VIDEO PLAYBACK FIX
   Nothing else about the layout changes.

   The <video> was sized width:auto / height:auto. On a video those resolve
   to the intrinsic video size, which is unknown until metadata loads, so
   the element ends up only as wide as the picture. The browser draws its
   control bar inside THAT box, so on a portrait clip the bar was roughly
   345px wide — too narrow for Chrome to lay out a draggable scrub bar, and
   narrow enough that the bar looked missing. On iOS the same thing put the
   full-screen button off at the clipped top edge of the picture.

   The video element now fills its frame and object-fit keeps the picture
   exactly the same size and position as before. Only the element box
   changes, which gives the browser full width for a normal control bar.
   ========================================================================= */
/* Written with ID-level selectors as well, because portfolio.css sets these
   from ID rules and a plain class selector loses the tie. */
.pfCarousel .pfViewport .pfTrack .pfSlide video.pfVideo,
#modalMedia video.pfVideo,
#projectMedia video.pfVideo,
#fullMedia video.pfVideo,
#mediaLightbox .lightboxMedia video.pfVideo,
.projectModal video.pfVideo {
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  object-fit: contain !important;
  background: #000 !important;
}

/* The dots and counter sat along the bottom edge, which is now where the
   browser's control bar lives. On a video slide they move above it. */
.pfCarousel[data-kind="video"] .pfBar {
  bottom: 52px;
  background: none;
}

/* The browser puts its skip-10 buttons either side of centre. On a narrow
   frame those land right on our arrows, which is the overlap on mobile.
   On touch the arrows step aside on video slides — swipe still works, and
   the dots still show position. On any device they step aside while the
   video is playing. */
@media (pointer: coarse) {
  .pfCarousel[data-kind="video"] .pfNav { display: none !important; }
}
.pfCarousel[data-playing="1"] .pfNav { display: none !important; }
.pfCarousel[data-playing="1"] .pfBar { opacity: 0; transition: opacity .2s ease; }
