/* ============================================================
   Site-specific overrides on top of the Rubik template
   (assets/css/bootstrap.css + assets/css/styles.css).
   Paired with index.html. Grouped by the section each rule
   targets, not by when it was added.
============================================================ */

/* ---- misc / a11y ------------------------------------------ */
a:focus, a:active, .btn:focus, .btn:active, .btn:focus:active {
  outline: none !important;
  box-shadow: none !important;
}

.repo-link {
  color: #c9a52a;
  font-family: monospace;
  font-size: 14px;
  letter-spacing: 0.05em;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.2s, text-shadow 0.2s, border-color 0.2s;
}
.repo-link:hover {
  color: #c9a52a;
  text-shadow: 0 0 8px rgba(201, 165, 42, 0.7), 0 0 20px rgba(201, 165, 42, 0.4);
  border-bottom: 1px solid #c9a52a;
  text-decoration: none;
}

/* ---- hero portrait ------------------------------------------
   Crop/darken the hero photo to match the previous photo's
   moody, tightly-cropped treatment. */
/* Mobile browsers resize their visible viewport as the address bar
   collapses/expands on scroll, and plain vh units are recalculated
   against that changing height — so a section sized in vh visibly
   grows or shrinks a moment into every scroll. svh ("small viewport
   height") is pinned to the viewport size when browser chrome is
   fully shown and never changes, eliminating the jump. Declared
   after the vh fallback so unsupported browsers still get a height. */
#home.parallax {
  height: 100vh;
  height: 100svh;
}
@media (max-width: 768px) {
  #home.parallax {
    height: 80vh;
    height: 80svh;
  }
}
#home.parallax > img {
  object-fit: cover;
  object-position: 50% 22%;
  transform: scale(1.6);
  transform-origin: 50% 22%;
  filter: brightness(0.3) contrast(1.15) saturate(0.7);
}
/* Below ~992px width, script.js swaps the <img> above for a plain
   background-image div (see checkResponsiveImage in script.js) —
   it needs the same crop/darken treatment applied here separately.
   The template gives this div its own unconditional height: 80vh
   (assets/css/styles.css), while its parent only drops to 80vh under
   a max-width: 768px media query — so on any viewport from ~769 to
   991px wide (tablets, large phones) the two heights mismatch and a
   gap opens below the hero, showing the div's tan fallback
   background-color. Tying height to the parent (100%) and matching
   that fallback color to the hero makes the seam impossible at any
   width, and invisible even if a sub-pixel gap ever does occur. */
#home.parallax .responsive-background {
  height: 100%;
  background-color: #04060a;
  background-position: 50% 15%;
  background-size: 220% auto;
  filter: brightness(0.3) contrast(1.15) saturate(0.7);
}

/* ---- hero title + contact info (luxury pass) -----------------
   The template's default hard 3D drop-shadow on the hero title
   reads as dated; a single soft lift keeps it legible over the
   photo without the "stamped" look. */
#home .section-header h1,
.section-header h1 {
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.45);
}
/* Slim-Joe (the hero display font, also used for the "Todd Swepston"
   navbar brand) only ships one weight — thin — and there's no bold
   face to fall back on, so font-weight: bold does nothing real
   (browsers can only fake-skew it). At the smaller size mobile
   renders it at, the thin strokes get lost. A slim text-stroke in
   the same color visually thickens the actual glyphs instead. */
@media (max-width: 768px) {
  .section-header h1,
  .navbar-brand {
    -webkit-text-stroke: 0.6px currentColor;
    text-stroke: 0.6px currentColor;
  }
}

/* De-emphasize the hero contact info from two giant stacked lines
   into one quiet, tracked-out strip — the phone number doesn't
   need to shout as loud as the title. */
#home .content h5 {
  display: block;
  font-family: "Verlag-Book", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.85);
  text-shadow: none;
  margin: 0 0 10px;
}
#home .content h5:last-of-type {
  margin-bottom: 0;
}

/* ---- hero load-in sequence -------------------------------------
   Paired with assets/js/hero-intro.js, which splits the title into
   one <span class="hero-char"> per character and staggers each
   one's animation-delay. Title characters settle in first (blur +
   rise + fade), then the separator, then the contact info — a short
   choreographed "power-on" rather than everything appearing at once.
   Skipped under prefers-reduced-motion (the JS bails out entirely,
   so these rules simply never find anything to apply to). */
#home .hero-title-intro .hero-word {
  display: inline-block;
}
#home .hero-title-intro .hero-char {
  display: inline-block;
  opacity: 0;
  filter: blur(6px);
  transform: translateY(26px);
  animation: hero-char-in 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
#home .hero-title-intro .hero-char.space {
  width: 0.32em;
}
@keyframes hero-char-in {
  to { opacity: 1; filter: blur(0); transform: translateY(0); }
}

#home .separator-container {
  opacity: 0;
  transform: scale(0.9);
  animation: hero-scale-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: 1s;
}
#home .content h5,
#home .content > a.btn-social {
  opacity: 0;
  transform: translateY(12px);
  animation: hero-rise-in 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: 1.3s;
}
#home .content h5:nth-of-type(2) { animation-delay: 1.4s; }
#home .content > a.btn-social { animation-delay: 1.5s; }
@keyframes hero-scale-in { to { opacity: 1; transform: scale(1); } }
@keyframes hero-rise-in { to { opacity: 1; transform: translateY(0); } }

/* ---- project grid (luxury pass) -------------------------------
   Give the grid a slim, considered gutter instead of the
   template's edge-to-edge mosaic, and reveal each title on hover
   through a soft gradient scrim instead of no caption at all.
   This row has no .container wrapper to supply the padding that
   normally offsets Bootstrap's -15px row margin, so below the
   template's own 992px override that row overflowed its section
   by 30px on every phone/tablet width — zero it out unconditionally. */
.section-we-made-1.section-with-hover .row {
  margin: 0;
}
.section-we-made-1.section-with-hover .row [class^="col-"] {
  padding: 3px !important;
}
.section-with-hover .project-caption {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  align-items: flex-end;
  padding: 28px 24px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0) 55%);
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
}
.section-with-hover .project:hover .project-caption { opacity: 1; }
.section-with-hover .project-caption span {
  font-family: "Verlag-Book", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fff;
  transform: translateY(6px);
  transition: transform 0.35s ease;
}
.section-with-hover .project:hover .project-caption span { transform: translateY(0); }
.section-with-hover .project img { transition: transform 0.6s ease, filter 0.6s ease; }
.section-with-hover .project:hover img { transform: scale(1.035); }

/* Both the two featured images and the 21-tile grid open in the
   lightbox below on click. */
#projects .project,
.section-with-hover .project {
  cursor: pointer;
}

/* ---- lightbox -------------------------------------------------
   Paired with assets/js/lightbox.js. Click any project image to
   view it full-browser; close via the X, the backdrop, or Escape. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 6vh 5vw;
  background: rgba(4, 4, 4, 0.94);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}
.lightbox.open {
  opacity: 1;
  visibility: visible;
}
.lightbox figure {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  max-width: 100%;
  max-height: 100%;
  transform: scale(0.97);
  transition: transform 0.3s ease;
}
.lightbox.open figure {
  transform: scale(1);
}
.lightbox img {
  max-width: 88vw;
  max-height: 78vh;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
}
.lightbox figcaption {
  font-family: "Verlag-Book", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.75);
  text-align: center;
  min-height: 1em;
}
.lightbox-close {
  position: fixed;
  top: 24px;
  right: 28px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.3);
  background: rgba(255, 255, 255, 0.05);
  color: #fff;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s ease, transform 0.3s ease;
}
.lightbox-close:hover {
  background: rgba(255, 255, 255, 0.15);
  transform: rotate(90deg);
}
@media (max-width: 540px) {
  .lightbox-close { top: 14px; right: 14px; width: 40px; height: 40px; }
}

/* ---- small screens ------------------------------------------ */
@media (max-width: 768px) {
  .repo-link {
    padding: 0 24px;
    display: inline-block;
  }
  .intro-video-wrap {
    overflow: hidden;
    height: 56vw;
  }
  .intro-video-wrap video {
    width: 160% !important;
    margin-left: -30%;
    margin-top: -8%;
  }
}
