/* blog-page.css : the blog index's featured card + card grid (#850).
   Loaded by blog.html only, after site.css.

   HARD CONSTRAINT: apps/site/build-feed.py rewrites the whole
   <div class="article-list">...</div></div></section> block on every publish
   from a fixed card template, so the markup here can never be restructured by
   hand. Everything below is layout over the generated markup: the featured
   post is .article-card:first-child, its image comes from this stylesheet,
   and the issue numbers are CSS counters, not content. A new post landing at
   the top therefore becomes the featured card automatically. */

.article-list {
  --blog-featured-img: url("blog/01-approved-work-and-what-actually-ships.webp");
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.1rem, 2vw, 1.6rem);
  counter-reset: blog-issue;
  border-top: 0;
}

/* ---------------------------------------------------------------- cards */

.article-list .article-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .9rem;
  padding: clamp(1.3rem, 2.2vw, 1.9rem);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: #fff;
  counter-increment: blog-issue;
  transition: transform .28s cubic-bezier(.22, .61, .36, 1), box-shadow .28s ease, border-color .28s ease;
}

/* Big gold issue number, top-right. Decorative: aria-hidden is not available
   on a pseudo-element, so it stays out of the accessibility tree by being
   generated content with no semantic role. */
.article-list .article-card::before {
  content: counter(blog-issue, decimal-leading-zero);
  position: absolute;
  top: .55rem;
  right: .9rem;
  color: var(--gold-text);
  font-size: clamp(2.4rem, 4vw, 3.4rem);
  font-weight: 800;
  line-height: 1;
  opacity: .22;
  pointer-events: none;
}

.article-list .article-card .article-meta {
  position: relative;
  z-index: 1;
  max-width: 11rem;
}

.article-list .article-card > div { flex: 1 1 auto; }

.article-list .article-card h2 {
  margin-bottom: .55rem;
  font-size: clamp(1.3rem, 1.7vw, 1.65rem);
}

.article-list .article-card p { max-width: none; font-size: .95rem; }

.article-list .article-card .text-link { align-self: start; }

.article-list .article-card:hover,
.article-list .article-card:focus-within {
  transform: translateY(-4px);
  border-color: var(--gold);
  box-shadow: 0 14px 34px oklch(15% .06 18 / .14);
}

.article-list .article-card:hover h2,
.article-list .article-card:focus-within h2 {
  text-decoration: underline;
  text-decoration-color: var(--gold);
  text-decoration-thickness: 2px;
  text-underline-offset: .18em;
}

/* ------------------------------------------------------------- featured */

.article-list .article-card:first-child {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 55% minmax(0, 1fr);
  gap: clamp(1.4rem, 3vw, 2.6rem);
  /* Three content rows (meta, copy, link) packed to the middle of the card so
     the copy column centers against the image instead of sitting on the floor
     with dead space above the meta row (#850, 2026-10-07). */
  grid-template-rows: auto auto auto;
  align-content: center;
  align-items: center;
  padding: 0;
  overflow: hidden;
  border-color: transparent;
  background: var(--garnet-3);
  color: var(--cream);
}

.article-list .article-card:first-child::before {
  content: "";
  position: static;
  align-self: stretch;
  min-height: clamp(220px, 32vw, 400px);
  background: var(--blog-featured-img) center / cover no-repeat;
  opacity: 1;
  transform: scale(1);
  transform-origin: center;
  will-change: transform;
}

.article-list .article-card:first-child > * { padding-right: clamp(1.4rem, 3vw, 2.6rem); }
.article-list .article-card:first-child .article-meta {
  padding-top: clamp(1.4rem, 3vw, 2.4rem);
  color: var(--gold-soft);
  max-width: none;
}
.article-list .article-card:first-child h2 {
  color: var(--cream);
  font-size: clamp(1.7rem, 2.9vw, 2.5rem);
}
.article-list .article-card:first-child p { color: oklch(92% .012 80); }
.article-list .article-card:first-child .text-link {
  padding-bottom: clamp(1.4rem, 3vw, 2.4rem);
  color: var(--gold-soft);
}
.article-list .article-card:first-child:hover,
.article-list .article-card:first-child:focus-within {
  border-color: transparent;
}
.article-list .article-card:first-child:hover h2,
.article-list .article-card:first-child:focus-within h2 {
  text-decoration-color: var(--gold-bright);
}

/* The featured image is one grid cell, not a child of the copy column, so the
   copy needs its own stacking context to sit in column two. */
.article-list .article-card:first-child > div { grid-column: 2; }
.article-list .article-card:first-child > .article-meta { grid-column: 2; grid-row: 1; }
.article-list .article-card:first-child > div { grid-row: 2; }
.article-list .article-card:first-child > .text-link { grid-column: 2; grid-row: 3; }
.article-list .article-card:first-child::before { grid-column: 1; grid-row: 1 / -1; }

/* ---------------------------------------------------------------- motion */

/* The pre-enter state (opacity 0, translateY 16px) is set by blog-page.js with
   gsap.set, never here, so no-JS and reduced-motion readers get a fully
   visible page. */

/* Word mask reveal (blog-page.js wraps each word of a card title): the outer
   span clips, the inner one rises out of it. */
.wm-word { display: inline-block; overflow: hidden; vertical-align: bottom; }
.wm-in { display: inline-block; will-change: transform; }

/* The featured image shipped as a ::before pseudo-element, which GSAP cannot
   target and which cannot hold a parallax layer of its own. When the script
   runs it adds .blog-art-js and a real .blog-art frame in the same grid cell:
   the frame owns the clip-path reveal, the inner .blog-art-img is 112% tall so
   the scrubbed +-6% parallax never exposes an edge. No JS keeps the pseudo. */
.article-list .article-card:first-child.blog-art-js::before { content: none; display: none; }
.article-list .article-card:first-child > .blog-art {
  grid-column: 1;
  grid-row: 1 / -1;
  align-self: stretch;
  display: block;
  position: relative;
  min-height: clamp(220px, 32vw, 400px);
  padding-right: 0;
  overflow: hidden;
  will-change: clip-path;
}
.article-list .article-card:first-child > .blog-art > .blog-art-img {
  position: absolute;
  inset: -6% 0;
  display: block;
  height: 112%;
  background: var(--blog-featured-img) center / cover no-repeat;
  will-change: transform;
}

/* ------------------------------------------------------------ breakpoints */

@media (max-width: 1099px) {
  .article-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 760px) {
  .article-list { grid-template-columns: 1fr; }
  .article-list .article-card:first-child {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto auto;
    align-content: start;
    padding-bottom: 0;
  }
  .article-list .article-card:first-child::before,
  .article-list .article-card:first-child > .blog-art {
    grid-column: 1;
    grid-row: 1;
    min-height: 190px;
  }
  .article-list .article-card:first-child > .article-meta { grid-column: 1; grid-row: 2; padding-left: 1.2rem; }
  .article-list .article-card:first-child > div { grid-column: 1; grid-row: 3; padding-left: 1.2rem; }
  .article-list .article-card:first-child > .text-link { grid-column: 1; grid-row: 4; padding-left: 1.2rem; }
  .article-list .article-card:first-child > * { padding-right: 1.2rem; }
}
