/* Phoenix Prime Focus — component styles.
   Plain CSS (no @apply): the Play CDN only compiles utilities it finds in markup,
   so component classes live here and survive the move to a CLI build unchanged.
   Every value resolves to a design-system token. */

/* ---------- base ---------- */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
:focus-visible { outline: 2px solid var(--pf-flame); outline-offset: 2px; }

/* ---------- header ---------- */
#site-header { background: linear-gradient(to bottom, rgba(0,0,0,.75), rgba(0,0,0,0)); }
/* The solid bar is a layer that fades in, not a background swap. A gradient and a flat
   colour cannot interpolate, so transitioning between them snapped mid-way and the hero
   flashed through for a frame. Opacity animates on the compositor and always can. */
#site-header::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--pf-black); opacity: 0;
  transition: opacity var(--duration-base) var(--ease-standard);
}
#site-header[data-scrolled="true"]::before { opacity: 1; }

.site-nav { display: flex; align-items: center; gap: clamp(18px, 3vw, 40px); }

.nav-link {
  font-family: var(--font-label); font-size: var(--text-label); font-weight: var(--weight-label);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--pf-white); text-decoration: none; border-bottom: 0;
  transition: color var(--duration-fast) var(--ease-standard);
}

/* Hamburger. Square like everything else, 44px so it is a real touch target even
   though the glyph is 26px. */
.nav-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: none; margin-right: -10px;
  background: transparent; border: 0; border-radius: var(--radius-none);
  color: var(--pf-white); cursor: pointer;
  transition: color var(--duration-fast) var(--ease-standard);
}
.nav-toggle__close { display: none; }
.nav-toggle[aria-expanded="true"] .nav-toggle__open { display: none; }
.nav-toggle[aria-expanded="true"] .nav-toggle__close { display: block; }

/* Below md the four items wrapped under the logo — onto two rows on a phone — taking
   the header from 108px to 199px. There they collapse into a panel under the bar. */
@media (max-width: 767px) {
  .site-nav {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    padding: 4px clamp(20px,4vw,56px) 24px;
    background: var(--pf-black);
    border-top: var(--border-hairline) solid var(--border-on-inverse);
    /* display: none cannot transition. visibility keeps the closed panel out of the
       tab order while opacity and transform carry the movement. */
    opacity: 0; visibility: hidden; transform: translateY(-6px);
    transition: opacity var(--duration-base) var(--ease-standard),
                transform var(--duration-base) var(--ease-standard),
                visibility 0s linear var(--duration-base);
  }
  .site-nav[data-open="true"] {
    opacity: 1; visibility: visible; transform: none;
    transition: opacity var(--duration-base) var(--ease-standard),
                transform var(--duration-base) var(--ease-standard),
                visibility 0s;
  }
  .site-nav .nav-link {
    padding: 18px 0;
    border-bottom: var(--border-hairline) solid var(--border-on-inverse);
  }
  .site-nav .pf-btn { margin-top: 24px; justify-content: center; }
  /* An open panel needs the bar solid behind it, whatever the scroll position. */
  #site-header[data-menu="open"]::before { opacity: 1; }
}

/* ---------- eyebrow (the brand's signature type gesture) ---------- */
.eyebrow {
  display: flex; align-items: center; gap: 14px; margin: 0;
  font-family: var(--font-label); font-size: var(--text-label); font-weight: var(--weight-label);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
}
/* The rule takes the eyebrow's own colour rather than a fixed one, so the pair always
   reads as a single mark: ember on light grounds, flame on the black sections. */
.eyebrow-rule { display: block; flex: none; width: 26px; height: 2px; background: currentColor; }

/* ---------- section heading ---------- */
.section-title {
  margin: 20px 0 0;
  font-family: var(--font-display); font-weight: var(--weight-display);
  font-size: var(--text-h2); line-height: var(--leading-heading);
  letter-spacing: var(--tracking-display); text-transform: uppercase;
}

/* ---------- product card ---------- */
.card {
  min-width: 0; background: var(--pf-white);
  border: var(--border-hairline) solid var(--border-subtle);
  border-radius: var(--radius-none);
  transition: border-color var(--duration-base) var(--ease-standard);
}
.card--dark { background: var(--pf-black); border-color: var(--pf-black); color: var(--pf-white); }

.card-title {
  font-family: var(--font-display); font-size: var(--text-h4); font-weight: var(--weight-display-strong);
  letter-spacing: var(--tracking-display); text-transform: uppercase;
}
.card-specs {
  margin: 10px 0 0;
  font-family: var(--font-label); font-size: var(--text-label); font-weight: var(--weight-label);
  letter-spacing: var(--tracking-label); text-transform: uppercase; line-height: 1.7;
  color: var(--pf-ember);
}
.card-text { margin: 16px 0 0; font-size: 15px; line-height: 1.6; color: var(--pf-grey-600); }

/* ---------- image placeholder ----------
   Holds the exact aspect box before the photo exists, so dropping the real file in
   later shifts nothing. data-label / data-size render as the placeholder caption. */
.ph {
  position: relative; overflow: hidden; background: #0A0A0A;
  display: grid; place-content: center; justify-items: center;
  gap: 6px; padding: 16px; text-align: center;
}
.ph:not(.is-loaded) { box-shadow: inset 0 0 0 1px #262626; }
.ph::before {
  content: attr(data-label);
  font-family: var(--font-label); font-size: 11px; font-weight: var(--weight-label);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: #8A8A8A;
}
.ph::after {
  content: attr(data-size);
  font-family: var(--font-data); font-size: 11px;
  letter-spacing: var(--tracking-label-tight); color: #5A5A5A;
}
.ph--corner { place-content: end; justify-items: end; padding: 24px; text-align: right; }

.ph-img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0;
  transition: opacity var(--duration-slow) var(--ease-out);
}
.ph.is-loaded .ph-img { opacity: 1; }
.ph.is-loaded::before, .ph.is-loaded::after { content: none; }

/* ---------- Custom Design ----------
   The photograph bleeds to the right edge of the viewport while the copy stays on the
   page's 1320px content grid, so its text lines up with every other section heading
   however wide the window gets. Same max()/calc() alignment the carousel track uses. */
.custom-copy {
  padding-left: max(clamp(20px,4vw,56px), calc((100vw - 1320px) / 2 + clamp(20px,4vw,56px)));
  padding-right: clamp(20px,4vw,56px);
  padding-top: clamp(64px,9vw,112px);
}

/* ---------- projects carousel ---------- */
/* The active slide is centred in the viewport, which also leaves an equal sliver of
   the previous and next slide on either side. The track sits one slot to the left
   (see the transform in site.js), so the current slide lands exactly on this padding. */
#projects-track {
  --s: min(78vw, 1040px);
  --g: clamp(16px, 2vw, 32px);
  gap: var(--g);
  padding-left: calc((100vw - var(--s)) / 2);
}
.project { flex: 0 0 var(--s); min-width: 0; margin: 0; }
.project-caption {
  margin-top: 18px; display: flex; flex-wrap: wrap; gap: 0;
  font-family: var(--font-label); font-size: clamp(11px, 1.1vw, 14px); font-weight: var(--weight-label);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--pf-black);
}
/* The dash belongs to the one-line form, so it lives here rather than in the markup.
   Its left margin is short of the space on the right by exactly one 0.24em tracking
   step, because the name before it already carries that step inside its own box —
   without the compensation the dash reads as sitting too far from the name. */
.project-caption span::before { content: "\2013\00a0"; margin-left: 0.54em; }

/* Below sm the longest captions wrapped and the shortest didn't, so the column read
   raggedly. Put the location on its own line for every project instead, and drop the
   dash, which only makes sense when the two sit side by side. */
@media (max-width: 639px) {
  .project-caption { flex-direction: column; gap: 6px; }
  .project-caption span::before { content: none; }
}

.nav-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 52px; height: 52px; flex: none;
  background: transparent; border: var(--border-hairline) solid var(--pf-black);
  border-radius: var(--radius-none); color: var(--pf-black); cursor: pointer;
  transition: var(--transition-control);
}

/* ---------- links ---------- */
.contact-link { font-size: 17px; color: var(--pf-white); text-decoration: none; border-bottom: 0; transition: color var(--duration-fast) var(--ease-standard); }
.social-link { display: block; color: var(--pf-white); border-bottom: 0; transition: color var(--duration-fast) var(--ease-standard); }

/* ---------- Button — mirrors components/core/Button.jsx ---------- */
.pf-btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-label); font-weight: var(--weight-label);
  letter-spacing: var(--tracking-label-tight); text-transform: uppercase; line-height: 1;
  border: var(--border-hairline) solid transparent; border-radius: var(--radius-none);
  text-decoration: none; cursor: pointer;
  transition: var(--transition-control);
}
.pf-btn--sm { gap: 8px;  padding: 8px 16px;  font-size: var(--text-label); }
.pf-btn--md { gap: 10px; padding: 13px 24px; font-size: var(--text-label-lg); }
.pf-btn--lg { gap: 12px; padding: 18px 36px; font-size: 16px; }
.pf-btn--sm .pf-icon { width: 14px; height: 14px; }
.pf-btn--md .pf-icon { width: 16px; height: 16px; }
.pf-btn--lg .pf-icon { width: 18px; height: 18px; }
.pf-icon { flex: none; }

.pf-btn--primary { background: var(--accent); color: var(--text-on-accent); }
.pf-btn--primary:active { background: var(--accent-active); }

.pf-btn--secondary { background: transparent; color: var(--text-primary); border-color: var(--border-strong); }
.pf-btn--secondary.pf-btn--inverse { color: var(--pf-white); border-color: var(--border-on-inverse); }

.pf-btn:active { transform: translateY(1px); }           /* press nudges 1px — never a scale */

/* ---------- hover states ----------
   A touch device keeps :hover applied after a tap until something else is tapped,
   so a tapped control stayed lit — most visibly the hamburger, which held its flame
   colour after opening the menu. Hover is only offered where a pointer exists;
   :active and :focus-visible, which touch handles correctly, stay outside. */
@media (hover: hover) {
  .nav-link:hover { color: var(--pf-flame); }
  .nav-toggle:hover { color: var(--pf-flame); }
  .card:hover { border-color: var(--pf-flame); }          /* border moves to flame — no lift, no shadow */
  .card--dark:hover { border-color: var(--pf-flame); }
  .nav-btn:hover { background: var(--pf-black); color: var(--pf-sand); }
  .contact-link:hover { color: var(--pf-flame); }
  .social-link:hover { color: var(--pf-flame); }
  .pf-btn--primary:hover { background: var(--accent-hover); }
  .pf-btn--secondary:hover { background: var(--pf-black); color: var(--pf-white); }
  .pf-btn--secondary.pf-btn--inverse:hover { background: var(--pf-white); color: var(--pf-black); }
}
