/*
 * home.css — Home page layout and motion.
 *
 * Scoped to body.home-page so other pages can share the same shell HTML
 * without inheriting Home-specific styles. Tokens come from tokens.css;
 * page-level padding is defined here because 40px / 20px don't fit the
 * 8px global spacing scale but are page-wide concerns.
 *
 * BUILD_SPEC.md §5.1 (Home), §2 (animation vocabulary).
 *
 * Layered structure (z-index from tokens):
 *   .cover-stage (--z-content) — two .cover-layer siblings for the sweep
 *   .home-content (--z-info)   — title, role, info row sit above the cover
 *   .site-header (--z-header)
 *   .placeholder-screen (--z-fullscreen) — shown only when route !== home
 */

.home-page {
  --page-pad-x: 40px;
  --page-pad-y: 20px;
  overflow: hidden; /* Home is fixed-bleed; nothing scrolls */
  touch-action: none; /* Prevent browser scroll-cancel (pointercancel) on touch swipe */
}

/* ---------- Cover stage ---------- */

.cover-stage {
  position: fixed;
  inset: 0;
  z-index: var(--z-content);
  background-color: var(--color-bg-dark);
}

.cover-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  /* Hidden by default; the active layer gets its clip-path cleared by JS. */
  clip-path: inset(0 0 0 100%);
  -webkit-clip-path: inset(0 0 0 100%);
  z-index: 0;
}

.cover-layer.is-active {
  clip-path: inset(0 0 0 0);
  -webkit-clip-path: inset(0 0 0 0);
  z-index: 1;
}

/* The animating layer always sits above the active one. Without this, a
 * "prev" sweep (where the new active layer is earlier in DOM order) would
 * wipe behind the currently-visible layer and be invisible. */
.cover-layer.is-animating {
  transition:
    clip-path var(--dur-sweep) var(--ease-sweep),
    -webkit-clip-path var(--dur-sweep) var(--ease-sweep);
  z-index: 2;
}

.cover-layer > video,
.cover-layer > img {
  width: 100%;
  height: 100%;
  display: block;
}

.cover-layer img,
.cover-layer video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* ---------- Site header ---------- */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--page-pad-y) var(--page-pad-x);
  color: var(--color-fg-dark);
  pointer-events: none; /* re-enabled on actionable children */
}

.site-logo,
.site-nav a {
  pointer-events: auto;
}

/* SVG logomark — see /assets/morro-logo.svg. The link element is
 * empty in the HTML (its accessible name comes from aria-label); CSS
 * draws the mark as a mask filled by currentColor, so the existing
 * page text-color cascade automatically renders the logo white on
 * the dark home backgrounds and black on white sub-pages. The
 * aspect ratio matches the SVG's viewBox so the link auto-widens
 * proportionally when the height changes.
 *
 * align-self: flex-start pins the logo to the TOP of the header's
 * flex line, regardless of how tall the other flex children are
 * (e.g., the 36px Contact icon on home). Without this, align-items:
 * center on the header would push the logo down to the visual
 * center of the icon-inflated row, making its position differ from
 * project/contact pages (where the logo is the only flex child).
 * With flex-start, the logo's top edge always sits at the header
 * padding-top — same Y on all three pages. */
.site-logo {
  display: inline-block;
  align-self: flex-start;
  margin-top: 6px;
  height: 32px;
  aspect-ratio: 1651.25 / 597.98;
  background-color: currentColor;
  mask-image: url('/assets/morro-logo.svg');
  -webkit-mask-image: url('/assets/morro-logo.svg');
  mask-size: contain;
  -webkit-mask-size: contain;
  mask-repeat: no-repeat;
  -webkit-mask-repeat: no-repeat;
  mask-position: left center;
  -webkit-mask-position: left center;
  color: inherit;
  text-decoration: none;
}

.site-nav a {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-logo);
  font-weight: var(--fw-regular);
  color: inherit;
  text-decoration: none;
  transition: opacity var(--dur-ui) var(--ease-ui);
}

.site-nav-icon {
  display: block;
  height: 36px;
  width: auto;
}

.site-nav a:hover,
.site-nav a:focus-visible {
  opacity: 0.7;
}

/* ---------- Home content (title, role, info row) ---------- */

.home-content {
  position: relative;
  z-index: var(--z-info);
  color: var(--color-fg-dark);
  height: 100vh;
  height: 100dvh;
  pointer-events: none;
}

.home-content > * {
  pointer-events: auto;
}

.project-title,
.project-role {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
}

.project-title {
  left: var(--page-pad-x);
  font-size: var(--fs-title);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: -0.03em;
  max-width: min(58vw, 70ch);
  cursor: pointer;
}

.project-role {
  right: var(--page-pad-x);
  font-size: var(--fs-role);
  font-weight: var(--fw-extralight);
  line-height: var(--lh-tight);
  text-align: right;
  max-width: 40vw;
}

/* ---------- Info row ---------- */

/* CSS grid with fixed-width columns so LOCATION, YEAR, and DESCRIPTION
 * always start at the same X position regardless of which project is
 * showing. Column widths scale with viewport via clamp() but are
 * constant per viewport, so the columns never shift between projects.
 * LOCATION is now single-city only (BUILD_SPEC.md v1.4 §6.1 Appendix C),
 * so the column can be much narrower than the v1.3 sizing. */
.info-row {
  position: fixed;
  left: var(--page-pad-x);
  right: var(--page-pad-x);
  bottom: calc(var(--page-pad-y) + var(--space-2));
  margin: 0;
  display: grid;
  grid-template-columns:
    clamp(80px, 8vw, 110px)
    clamp(50px, 5vw, 70px)
    1fr;
  column-gap: clamp(12px, 2vw, 32px);
  align-items: end;
  color: var(--color-fg-dark);
}

.info-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
}

.info-cell dt {
  /* Used to be clamp(10px, 0.7vw, 12px) — dropped the responsive
   * shrink because the narrow-viewport size read as too small. */
  font-size: 12px;
  font-weight: var(--fw-light);
  letter-spacing: var(--ls-label);
  opacity: 0.7;
}

.info-cell dd {
  margin: var(--space-1) 0 0;
  /* Same fixed-at-the-max treatment as dt above. */
  font-size: 16px;
  font-weight: var(--fw-light);
  line-height: var(--lh-snug);
  white-space: normal;
}

@media (max-width: 599px) {
  /* Mobile Home: title and role stack in a flex column pinned to the bottom
   * of .home-content. The margin-bottom on .project-title is the fixed gap
   * between title and role — constant regardless of how many lines the role
   * wraps to (previously the gap shrank as the role grew, because both
   * elements used independent fixed bottom values). */
  .info-row {
    display: none;
  }

  /* Flex column anchored at the bottom; padding-bottom replaces the old
   * role bottom: 56px (same visual anchor for the role's lower edge). */
  .home-content {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: 0 var(--page-pad-x) 56px;
  }

  .project-title {
    /* relative keeps the element as a containing block for the absolute
     * slot overlays while participating in the flex column flow. */
    position: relative;
    top: auto;
    bottom: auto;
    left: auto;
    right: auto;
    transform: none;
    font-size: var(--fs-title-mobile);
    max-width: none;
    margin: 0 0 var(--space-4); /* fixed gap to role below */
  }

  .project-role {
    position: relative;
    top: auto;
    bottom: auto;
    left: auto;
    right: auto;
    transform: none;
    text-align: left;
    max-width: none;
    font-size: clamp(16px, 4vw, 20px);
    margin: 0;
  }

}

/* ---------- Text slot animation (legacy slide-up-out / slide-up-in) ----------
 * Each text element wraps two .slot-clip layers: the visible one (data-slot-current)
 * and the queued one (data-slot-next). On project change the current slides out
 * (up for "next" direction, down for "prev") while the next slides in from below
 * (or above). Duration and easing match the cover sweep so the motion is unified.
 */

.slot-clip {
  display: block;
  overflow: hidden;
  line-height: inherit;
}

.project-title .slot-clip,
.project-role .slot-clip {
  display: inline-block;
  vertical-align: baseline;
}

.info-cell dd .slot-clip {
  display: inline-block;
  vertical-align: baseline;
}

/* info-cell dd is in normal flow inside the flex row; promote it to a
 * positioned ancestor so the absolute overlay anchors to the dd box. The
 * title and role are already position: fixed (above), which suffices. */
.info-cell dd {
  position: relative;
}

/* The aria-hidden slot-clip overlays the visible slot during a sweep.
 * width: max-content lets it fit its own (potentially longer) text instead
 * of being constrained to the current text's width, which would force the
 * incoming text to clip or wrap. The anchor (left vs right) matches the
 * parent's text-align so the overlay sits exactly where the in-flow current
 * slot-clip does. */
.project-title .slot-clip[aria-hidden="true"],
.info-cell dd .slot-clip[aria-hidden="true"] {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: max-content;
  pointer-events: none;
}

.project-role .slot-clip[aria-hidden="true"] {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: max-content;
  pointer-events: none;
}

/* On mobile the role becomes left-aligned (see media query above), so its
 * overlay anchor flips too. */
@media (max-width: 599px) {
  .project-role .slot-clip[aria-hidden="true"] {
    right: auto;
    left: 0;
  }

  .project-title .slot-clip[aria-hidden="true"] {
    top: auto;
    bottom: 0;
    width: 100%;
  }

  .project-title .slot-clip {
    vertical-align: bottom;
  }
}

.slot {
  display: inline-block;
  transform: translateY(0);
  clip-path: inset(0 0 0 0);
  -webkit-clip-path: inset(0 0 0 0);
  line-height: inherit;
  will-change: transform, clip-path;
}

.slot.is-leaving-up {
  transform: translateY(-40px);
  clip-path: inset(0 0 100% 0);
  -webkit-clip-path: inset(0 0 100% 0);
}

.slot.is-leaving-down {
  transform: translateY(40px);
  clip-path: inset(100% 0 0 0);
  -webkit-clip-path: inset(100% 0 0 0);
}

.slot.is-entering-up-prep {
  transform: translateY(40px);
  clip-path: inset(0 0 100% 0);
  -webkit-clip-path: inset(0 0 100% 0);
  transition: none;
}

.slot.is-entering-down-prep {
  transform: translateY(-40px);
  clip-path: inset(100% 0 0 0);
  -webkit-clip-path: inset(100% 0 0 0);
  transition: none;
}

.slot.is-animating {
  transition:
    transform var(--dur-sweep) var(--ease-sweep),
    clip-path var(--dur-sweep) var(--ease-sweep),
    -webkit-clip-path var(--dur-sweep) var(--ease-sweep);
}

/* ---------- Placeholder screen (non-Home routes in Phase 5) ---------- */

.placeholder-screen {
  position: fixed;
  inset: 0;
  z-index: var(--z-fullscreen);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
  padding: var(--page-pad-y) var(--page-pad-x);
  background-color: var(--color-bg-dark);
  color: var(--color-fg-dark);
  text-align: center;
}

.placeholder-screen[hidden] {
  display: none;
}

.placeholder-message {
  margin: 0;
  font-size: var(--fs-cta);
  font-weight: var(--fw-light);
  letter-spacing: var(--ls-display);
  opacity: 0.85;
}

.placeholder-back {
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* ---------- Reduced motion ----------
 * reset.css already nukes long animations and transitions; this rule makes
 * sure cover layers don't get stuck in their hidden clip-path state.
 */
@media (prefers-reduced-motion: reduce) {
  .cover-layer:not(.is-active) {
    visibility: hidden;
  }
}

/* ---------- Next project timer button ----------
 *
 * Shown only on hover-capable desktop (≥600px). Hidden on touch devices
 * and narrow viewports so it never overlaps the mobile layout.
 *
 * The text gradient sweep is driven entirely by JS via three CSS custom
 * properties set every rAF frame:
 *   --progress   (0–1)  position of the bright/dim boundary
 *   --left-op    (0–1)  opacity of the left (bright) portion
 *   --right-op   (0–1)  opacity of the right (dim) portion
 *
 * The arrow uses the same slide-up-from-clip pattern as .title-arrow.
 * On hover the text shifts right to reveal the arrow (same translateX
 * trick as the project title hover affordance above).
 */

.next-btn {
  position: fixed;
  right: var(--page-pad-x);
  bottom: calc(var(--page-pad-y) + var(--space-2));
  z-index: var(--z-info);
  display: none;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--color-fg-dark);
  font-family: var(--font-primary);
  font-size: var(--fs-role);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: -0.03em;
}

.next-btn-text {
  display: block;
  background-image: linear-gradient(
    to right,
    rgba(255, 255, 255, var(--left-op,  0.9)) calc(var(--progress, 0) * 100%),
    rgba(255, 255, 255, var(--right-op, 0.4)) calc(var(--progress, 0) * 100%)
  );
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.next-btn-arrow-clip {
  display: none;
}

@media (hover: hover) and (pointer: fine) and (min-width: 600px) {
  .next-btn {
    display: block;
  }

  .next-btn-arrow-clip {
    display: block;
    position: absolute;
    right: 0;
    top: 50%;
    width: 0.6em;
    height: 0.6em;
    margin-top: -0.3em;
    overflow: hidden;
    pointer-events: none;
  }

  .next-btn-arrow {
    display: block;
    width: 100%;
    height: 100%;
    transform: translateY(100%);
    transition: transform 280ms cubic-bezier(.33, 1, .55, 1);
  }

  .next-btn-text {
    transition: transform 280ms cubic-bezier(.33, 1, .55, 1);
  }

  .next-btn:hover .next-btn-arrow {
    transform: translateY(0);
  }

  .next-btn:hover .next-btn-text {
    transform: translateX(-0.7em);
  }
}

/* ---------- Project title hover affordance ----------
 *
 * On hover of the home project title, a small diagonal arrow slides
 * up from below a clipping mask at the title's left edge, and the
 * title text shifts right by enough to make room for it. On hover
 * out, the arrow slides back down behind the clip and the text
 * returns. Hint to the user: "this is a link, click to view this
 * project."
 *
 * Performance: all four animated properties (transform on slot-clip,
 * transform on the arrow svg) are composite-only — no layout or
 * paint of the document. The arrow's wrapper is absolutely
 * positioned, so showing/hiding it doesn't shift any sibling. The
 * title is position: fixed, which already acts as a positioned
 * ancestor for the absolute arrow wrapper (no extra position:
 * relative needed).
 *
 * Gated behind (hover: hover) and (pointer: fine) — coarse-pointer
 * devices (touch) see no arrow and no transform, since the visual
 * presupposes the user can hover before clicking. Also gated behind
 * (prefers-reduced-motion: no-preference) so the effect doesn't run
 * for users who've asked the OS to reduce motion.
 */
.title-arrow-clip {
  /* Hidden by default; activated by the media query below. */
  display: none;
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .title-arrow-clip {
    display: block;
    position: absolute;
    left: 0;
    /* Vertically center against the title's box. The line-height of
     * the title is tight (--lh-tight), so this lands the arrow at
     * roughly the visual center of the cap-height area. */
    top: 50%;
    width: 0.5em;
    height: 0.5em;
    margin-top: -0.25em; /* half the height — centers without conflicting with a transform */
    overflow: hidden;
    pointer-events: none;
  }

  .title-arrow {
    display: block;
    width: 100%;
    height: 100%;
    /* Resting state: parked one full height below the clip box, so
     * the clip masks it completely. */
    transform: translateY(100%);
    transition: transform 280ms cubic-bezier(.33, 1, .55, 1);
  }

  /* Slot-clips wrap the visible and queued project titles. Shift
   * both on hover so the text moves uniformly out of the arrow's
   * way. The inner .slot already has its own transform for the
   * project-switch animation (translateY + clip-path); since our
   * translateX is on the parent slot-clip, the two transforms apply
   * to separate elements and don't conflict. */
  .project-title .slot-clip {
    transition: transform 280ms cubic-bezier(.33, 1, .55, 1);
  }

  .project-title:hover .title-arrow {
    transform: translateY(0);
  }

  .project-title:hover .slot-clip {
    transform: translateX(0.7em);
  }
}
