/* Portfolio UI kit — extends colors_and_type.css with kit-level layout. */
@import url("colors_and_type.css");

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; min-height: 100%; }
body {
  background: var(--bg-base);
  color: var(--fg-1);
  font-family: var(--font-sans);
}

/* Nav pill — labels on wide screens, icons on narrow.
   Each pill link renders both a .pill-icon and a .pill-label; the breakpoint
   controls which is shown. The icon-only state tightens horizontal padding. */
.pill-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.pill-link .pill-icon  { display: none; line-height: 0; }
.pill-link .pill-label { display: inline; }

@media (max-width: 760px) {
  .pill-link .pill-icon  { display: inline-flex; }
  .pill-link .pill-label { display: none; }
  /* In icon mode, the nav glyphs match the theme toggle's 24px size. */
  .pill-link .pill-icon .icon {
    width: 24px !important;
    height: 24px !important;
  }
  /* In icon mode the chip styling falls away: no padding chip, no background,
     no shadow. The icon glyph itself changes color to indicate active. */
  .pill-link {
    padding: 6px !important;
    gap: 0;
    background: transparent !important;
    box-shadow: none !important;
    color: var(--fg-2) !important;
  }
  .pill-link:hover           { color: var(--fg-1) !important; }
  .pill-link.is-active       { color: var(--iris-500) !important; }
  .pill-link.is-active:hover { color: var(--iris-400) !important; }

  /* Pair the icon-mode pill with a 25% smaller logo. The wrapper keeps its
     full height so the smaller glyph stays vertically centered with the pill. */
  .logo-link svg,
  .logo-link img {
    width: 37.5px !important;
    height: 37.5px !important;
  }
}

/* Theme toggle — sliding track on tablet/desktop, plain icon button on mobile.
   Breakpoint matches the nav pill's icon/label switch (760px). */
.theme-slider  { display: inline-flex; }
.theme-slider-always { display: inline-flex; }
.theme-iconbtn { display: none; }
@media (max-width: 760px) {
  .theme-slider  { display: none; }
  .theme-iconbtn { display: grid; }
}

/* Page atmospheric glow — three blobs each touring the four corners of the viewport, clockwise. */
.page-bg {
  position: fixed; inset: 0;
  background: var(--bg-base);
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}
.page-bg::before,
.page-bg::after,
.page-bg .blob-mauve {
  position: absolute;
  top: 0; left: 0;
  border-radius: 50%;
  filter: blur(40px);
  will-change: transform;
}
/* Iris — biggest, leads */
.page-bg::before {
  content: "";
  width: 90vw;
  aspect-ratio: 1;
  margin: -45vw 0 0 -45vw;       /* center the blob on the anchor point */
  background: radial-gradient(circle, rgba(138,114,214,0.42) 0%, rgba(138,114,214,0) 60%);
  animation: orbit-clockwise-tl 22s ease-in-out infinite;
}
/* Blush — starts top-right (quarter ahead) */
.page-bg::after {
  content: "";
  width: 70vw;
  aspect-ratio: 1;
  margin: -35vw 0 0 -35vw;
  background: radial-gradient(circle, rgba(247,168,196,0.22) 0%, rgba(247,168,196,0) 60%);
  animation: orbit-clockwise-tr 29s ease-in-out infinite;
}
/* Mauve — starts bottom-right (half ahead) */
.page-bg .blob-mauve {
  width: 60vw;
  aspect-ratio: 1;
  margin: -30vw 0 0 -30vw;
  background: radial-gradient(circle, rgba(212,167,232,0.18) 0%, rgba(212,167,232,0) 60%);
  animation: orbit-clockwise-br 37s ease-in-out infinite;
}

/* Each blob travels a clockwise loop around the viewport — but on its own "lane",
   inset by a different amount so the blobs never stack on the same corner. */

/* Iris — outer lane, hugs the edges */
@keyframes orbit-clockwise-tl {
  0%   { transform: translate(0,      0)    scale(1.00); }   /* TL */
  25%  { transform: translate(95vw,   0)    scale(1.10); }   /* TR */
  50%  { transform: translate(95vw,   85vh) scale(0.95); }   /* BR */
  75%  { transform: translate(0,      85vh) scale(1.08); }   /* BL */
  100% { transform: translate(0,      0)    scale(1.00); }   /* TL */
}
/* Blush — middle lane, inset ~18vw / 14vh; starts at TR for phase offset */
@keyframes orbit-clockwise-tr {
  0%   { transform: translate(78vw,   14vh) scale(1.00); }   /* TR */
  25%  { transform: translate(78vw,   72vh) scale(1.18); }   /* BR */
  50%  { transform: translate(18vw,   72vh) scale(0.92); }   /* BL */
  75%  { transform: translate(18vw,   14vh) scale(1.10); }   /* TL */
  100% { transform: translate(78vw,   14vh) scale(1.00); }   /* TR */
}
/* Mauve — inner lane, inset ~35vw / 28vh; starts at BR for phase offset */
@keyframes orbit-clockwise-br {
  0%   { transform: translate(62vw,   58vh) scale(1.00); }   /* BR */
  25%  { transform: translate(35vw,   58vh) scale(1.20); }   /* BL */
  50%  { transform: translate(35vw,   28vh) scale(0.90); }   /* TL */
  75%  { transform: translate(62vw,   28vh) scale(1.12); }   /* TR */
  100% { transform: translate(62vw,   58vh) scale(1.00); }   /* BR */
}

@media (prefers-reduced-motion: reduce) {
  .page-bg::before,
  .page-bg::after,
  .page-bg .blob-mauve { animation: none; }
}

/* — Subtle dot grid paper texture sitting above the colored blobs. — */
.page-bg .dot-grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: radial-gradient(circle, rgba(237, 233, 254, 0.08) 1px, transparent 1.2px);
  background-size: 22px 22px;
  background-position: 0 0;
  z-index: 1;
  mix-blend-mode: screen;
}

.container {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--gutter);
  position: relative;
  z-index: 1;
}

/* — Icon helper — SVG via CSS mask so it picks up currentColor — */
.icon {
  display: inline-block;
  width: 20px; height: 20px;
  background-color: currentColor;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-size: contain;
  vertical-align: middle;
  flex-shrink: 0;
}

/* — Buttons — */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: inherit; font-weight: 600; font-size: 14px;
  padding: 11px 18px; border-radius: 12px;
  border: 1px solid transparent; cursor: pointer; user-select: none;
  transition: transform var(--dur-fast) var(--ease-out),
              background var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              color var(--dur-base) var(--ease-out);
  text-decoration: none;
}
.btn:active { transform: scale(0.98); }
.btn-primary { background: var(--iris-500); color: var(--iris-50); box-shadow: var(--shadow-brand); }
.btn-primary:hover { background: var(--iris-400); }
.btn-primary:active { background: var(--iris-700); }
.btn-accent  { background: var(--amber-500); color: #2A1A00; }
.btn-accent:hover  { background: var(--amber-400); color: var(--iris-900); }
.btn-secondary { background: #312B50; color: var(--iris-100); border-color: var(--border-default); }
.btn-secondary:hover { background: #3B345F; }
.btn-ghost { background: transparent; color: var(--fg-2); }
.btn-ghost:hover { background: rgba(237,233,254,0.06); color: var(--fg-1); }
.btn-lg { padding: 14px 22px; font-size: 16px; border-radius: 14px; }

/* — Eyebrow — */
.eyebrow {
  display: inline-block;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--iris-300);
}

/* — Section heading scaffolding — */
.section { padding: clamp(28px, 4.5vw, 56px) 0; position: relative; z-index: 1; }

/* — Hero fills exactly one screen before scrolling —
   The in-flow header row (logo + theme toggle) is 98px tall (Nav's
   PILL_H 50 + 48), so the hero takes the remaining viewport height and
   centers its content vertically. dvh keeps it correct on mobile where the
   browser chrome changes the usable height; vh is the fallback. — */
.hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  min-height: calc(100vh - 98px);
  min-height: calc(100dvh - 98px);
}

/* Bias the centered hero content upward so the nav-pill → eyebrow gap is ~40%
   tighter. The centered gap grows with viewport height, so the shift is a
   viewport-proportional translate (clamped at 0 so short screens never get
   pushed down). Purely visual — leaves the absolutely-positioned scroll hint
   and page height untouched. */
.hero .container {
  transform: translateY(min(0px, 112px - 20vh));
}

/* — Scroll-down hint: pinned to the bottom-centre of the hero (which fills the
     viewport). Minimal — a fading hairline above a thin chevron that drifts
     down with a gentle pulse. No boxed/round icon. — */
.scroll-hint {
  position: absolute;
  left: 50%;
  bottom: clamp(14px, 2.4vh, 28px);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 9px;
  color: var(--fg-3);
  text-decoration: none;
  z-index: 2;
  transition: opacity 240ms var(--ease-out), color var(--dur-base) var(--ease-out);
}
.scroll-hint:hover { color: var(--fg-1); }
.scroll-hint-line {
  width: 1px;
  height: 30px;
  background: linear-gradient(to bottom, transparent, currentColor);
  opacity: 0.5;
}
.scroll-hint-bob {
  display: grid;
  place-items: center;
  animation: scrollHintBob 1.8s ease-in-out infinite;
}
.scroll-hint-arrow {
  width: 11px;
  height: 11px;
  margin-top: -5px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  border-radius: 1px;
  transform: rotate(45deg);
}
@keyframes scrollHintBob {
  0%, 100% { transform: translateY(0); opacity: 0.45; }
  50%      { transform: translateY(5px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .scroll-hint-bob { animation: none; opacity: 0.85; }
}
.section-head { display: flex; flex-direction: column; gap: 5px; max-width: 720px; margin-bottom: clamp(16px, 2.5vw, 24px); }
.section-head h2 { margin: 0; }

/* — Reveal: subtle fade + 8px translate up — */
.reveal { opacity: 0; transform: translateY(8px); transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out); }
.reveal.in { opacity: 1; transform: translateY(0); }

/* ============================================================
   RESPONSIVE OVERRIDES
   All triggers ≤ 760px — matches the existing pill breakpoint.
   Wide layout (>760px, where the pill shows labels) is untouched.
   ============================================================ */

/* — Header row: the pill is fixed at top: 24px with height 50, so its vertical
     centerline is at y = 49. The in-flow row's min-height (98px = PILL_H + 48)
     places its center on the same line, keeping the logo + theme toggle
     vertically aligned with the pill at every breakpoint — including icon
     mode, where the logo glyph itself shrinks to 37.5px but its wrapper
     keeps the full 50px height to stay centered. — */

/* — About: stack portrait above caps; reduce caps columns. — */
@media (max-width: 880px) {
  .about-grid {
    grid-template-columns: 1fr !important;
  }
  .about-portrait {
    aspect-ratio: 16 / 10;
    min-height: 0 !important;
    max-height: 420px;
  }
  .about-caps {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
}
@media (max-width: 520px) {
  .about-portrait { aspect-ratio: 4 / 5; }
  .about-caps {
    grid-template-columns: 1fr !important;
  }
}

/* — Contact: stack the heading above the CTA; CTA fills width on mobile.
     Allow the long email button to wrap gracefully if needed. — */
@media (max-width: 720px) {
  .contact-grid {
    grid-template-columns: 1fr !important;
    align-items: flex-start !important;
  }
  .contact-cta {
    width: 100%;
    justify-content: center;
    white-space: normal;
    text-align: center;
    word-break: break-word;
  }
}
@media (max-width: 420px) {
  /* Tighten the contact email button so the email address doesn't
     overflow the rounded card on very narrow phones. */
  .contact-cta {
    font-size: 14px !important;
    padding: 12px 16px !important;
  }
}

/* — Project modal preview grid: only 2-col variant collapses to 1 on small screens. — */
@media (max-width: 720px) {
  .preview-grid-2 {
    grid-template-columns: 1fr !important;
  }
}

/* — Photography: masonry columns reduce on narrower screens. — */
@media (max-width: 880px) {
  .photo-grid { columns: 2 !important; }
}
@media (max-width: 560px) {
  .photo-grid { columns: 1 !important; }
}

/* — Section padding tightens on small screens to reduce dead vertical space. — */
@media (max-width: 520px) {
  .section { padding: 28px 0 !important; }
}

/* — Hero: tighten everything on small screens so it fits within
     a single iPhone 16 viewport (393×852) without being cut off. — */
@media (max-width: 520px) {
  /* Bias the content upward (more space reserved at the bottom) rather than
     dead-centering it, and leave room for the scroll hint. */
  .hero {
    justify-content: flex-start !important;
    padding: clamp(44px, 12vh, 110px) 0 96px !important;
  }
  .hero-eyebrow {
    margin-bottom: 16px !important;
    font-size: 18px !important;
  }
  .hero-headline {
    font-size: 44px !important;
    line-height: 1.03 !important;
    letter-spacing: -0.024em !important;
  }
  .hero-lede {
    margin-top: 16px !important;
    font-size: 17px !important;
    line-height: 1.5 !important;
    max-width: 30ch !important;
  }
  /* Keep the two CTAs side by side at their natural widths. */
  .hero-ctas {
    margin-top: 24px !important;
    flex-direction: row !important;
    flex-wrap: wrap !important;
    gap: 10px !important;
  }
  .hero-ctas .btn-lg {
    width: auto !important;
    max-width: none !important;
    justify-content: center !important;
    padding: 12px 18px !important;
    font-size: 14px !important;
    border-radius: 12px !important;
    min-height: 46px !important;
  }
  .hero-meta {
    margin-top: 26px !important;
    gap: 10px 16px !important;
    font-size: 12px !important;
  }
}

/* ============================================================
   LIGHT MODE OVERRIDES — kit-level
   Only inside [data-theme="light"]; dark mode untouched.
   ============================================================ */

/* Dot grid: switch to dark dots multiplied over the light page. */
:root[data-theme="light"] .page-bg .dot-grid {
  background-image: radial-gradient(circle, rgba(159, 142, 223, 0.18) 1px, transparent 1.2px);
  mix-blend-mode: multiply;
}

/* Eyebrow: iris-300 is too pale on white — use a deep iris. */
:root[data-theme="light"] .eyebrow {
  color: var(--iris-700);
}

/* About section: drop the dark vignette gradient on the light page. */
:root[data-theme="light"] #about {
  background: none !important;
}

/* Secondary button: dark iris text on soft purple. */
:root[data-theme="light"] .btn-secondary {
  color: var(--iris-700);
  background: #EEEAFA;
  border-color: var(--border-default);
}
:root[data-theme="light"] .btn-secondary:hover {
  background: #E2DAF5;
}

/* About capability cards: icon tile needs darker glyph for contrast. */
:root[data-theme="light"] .about-cap-icon {
  background: rgba(138, 114, 214, 0.14) !important;
  color: var(--iris-700) !important;
}

/* Contact card: hardcoded dark gradient — swap to a light one. */
:root[data-theme="light"] .contact-wrap {
  background: linear-gradient(135deg, #FFFFFF 0%, #ECE6FA 100%) !important;
  border: 1px solid var(--border-default) !important;
}
:root[data-theme="light"] .contact-wrap p {
  color: var(--fg-2);
}

/* Background blobs: tone down brightness in light mode so they don't wash out. */
:root[data-theme="light"] .page-bg::before {
  background: radial-gradient(circle, rgba(138, 114, 214, 0.16) 0%, rgba(138, 114, 214, 0) 60%);
}
:root[data-theme="light"] .page-bg::after {
  background: radial-gradient(circle, rgba(247, 168, 196, 0.10) 0%, rgba(247, 168, 196, 0) 60%);
}
:root[data-theme="light"] .page-bg .blob-mauve {
  background: radial-gradient(circle, rgba(212, 167, 232, 0.10) 0%, rgba(212, 167, 232, 0) 60%);
}

/* Hero amber accent: amber-500 is too pale on white — deepen for contrast. */
:root[data-theme="light"] .hero-amber {
  color: var(--amber-700) !important;
}

/* Project modal tags: iris-100 is invisible on light bg — use iris-700. */
:root[data-theme="light"] .pm-tag {
  color: var(--iris-700) !important;
  background: rgba(138, 114, 214, 0.12) !important;
}

/* — Large screens (≥1240px): the hero's fluid type and the inline lede size
     bottom out around the old 1240px container width, so on 27"+ monitors the
     headline stopped growing and the section read as empty. Resume fluid
     scaling from where the small/medium tiers leave off, climbing toward a
     ~2560px ceiling. !important is required because the sizes are set as inline
     React styles. Nothing below 1240px is affected. — */
@media (min-width: 1240px) {
  .hero {
    min-height: calc(100vh - 98px);
    min-height: calc(100dvh - 98px);
  }
  .hero-eyebrow {
    font-size: clamp(34px, calc(23px + 0.91vw), 46px) !important;
    margin-bottom: clamp(24px, 2.2vw, 34px) !important;
  }
  .hero-headline {
    font-size: clamp(82px, calc(50px + 2.58vw), 116px) !important;
    max-width: 1200px !important;
  }
  .hero-lede {
    font-size: clamp(19px, calc(14px + 0.38vw), 24px) !important;
    max-width: clamp(640px, 48vw, 760px) !important;
    line-height: 1.55 !important;
  }
  .hero-ctas {
    margin-top: clamp(36px, 3.4vw, 52px) !important;
  }
  .hero-meta {
    margin-top: clamp(48px, 4.4vw, 68px) !important;
    font-size: clamp(13px, calc(11px + 0.16vw), 16px) !important;
  }
}
