/* ==========================================================================
   Blog — replica of paulkalkbrenner.net/news (spec: docs/superpowers/specs/
   2026-09-23-blog-kalkbrenner-news.md). Rule bodies are copied from
   reference/kalkbrenner/{shared.css,odyn-bundle.css}; the only edits are
   (1) the fluid em system is scoped to `.blog` instead of :root/body,
   (2) their black/white tokens map to slate/wool,
   (3) their commercial ABC Diatype maps to Sora (headings) / Inter (copy),
   (4) article running copy gets a readable size/leading and measure
       (spec §4.2 Adapt): 1.25em/1.6 = 15px at 1440, 20px at 1920, over a
       42% column rather than the reference's 32%.
   Everything inside .blog is in em on purpose — 1em = 12px at 1440 and 16px
   at 1920. Do not convert to px.

   The one number that is NOT the reference's: the em itself has a floor.
   Each breakpoint restarts the clamp at its own --size-container-min, so the
   raw scale troughs at 8.3px just above 992 and 8.8px just above 768 —
   unreadable, and the reference gets away with it only because its pages are
   headline-sized. Hence `max(12px, var(--size-font))`.
   ========================================================================== */

/* ------------------------------------------------------------ 1. sizing */
.blog{
  --size-unit:16;
  --size-container-ideal:1920;
  --size-container-min:992px;
  --size-container-max:2560px;
  --size-container:clamp(var(--size-container-min),100vw,var(--size-container-max));
  --size-font:calc(var(--size-container) / (var(--size-container-ideal) / var(--size-unit)));
  --page-pad:.625em;
  --gap-s:.75em;--gap-ml:1.25em;--gap-l:1.5em;
  --col-pad:var(--gap-ml);
  --space-s:1em;--space-sm:2em;--space-m:7.5em;--space-l:10em;
  --col-count:8;
  --col-size-2:calc(100% * 2 / var(--col-count));
  --col-size-3:calc(100% * 3 / var(--col-count));
  --col-size-4:calc(100% * 4 / var(--col-count));
  --col-size-5:calc(100% * 5 / var(--col-count));
  --col-size-6:calc(100% * 6 / var(--col-count));
  --col-size-8:calc(100% * 8 / var(--col-count));
  --cubic-default:cubic-bezier(.625,.05,0,1);
  --animation-default:.7s var(--cubic-default);
  --color--dark:var(--slate);
  --color--light:var(--wool);
  --color--dark-20:color-mix(in srgb,var(--slate),transparent 80%);
  --color--dark-40:color-mix(in srgb,var(--slate),transparent 60%);
  font-size:max(12px,var(--size-font));
  line-height:1;
  font-family:var(--font-body);
  font-weight:400;
  color:var(--color--dark);
  background:var(--color--light);
  /* the copied grid overshoots the container by --page-pad a side */
  overflow-x:clip;
}
@media (max-width:991px){.blog{--size-container-ideal:1400;--size-container-min:768px;--size-container-max:991px}}
@media (max-width:767px){.blog{--size-container-ideal:700;--size-container-min:480px;--size-container-max:767px;--col-count:5}}
@media (max-width:479px){.blog{--size-container-ideal:390;--size-container-min:320px;--size-container-max:479px}}

/* -------------------------------------------------------------- 2. grid */
.blog .container{width:100%;padding-right:var(--page-pad);padding-left:var(--page-pad);margin-left:auto;margin-right:auto}
.blog .section{width:100%;padding-top:var(--space-s);padding-bottom:var(--space-s)}
.blog .row{margin-left:calc(-1 * var(--col-pad));margin-right:calc(-1 * var(--col-pad));flex-flow:wrap;display:flex}
.blog .col{padding-right:var(--col-pad);padding-left:var(--col-pad);flex:1}
.blog .u-col-2{max-width:var(--col-size-2)}
.blog .u-col-4{max-width:var(--col-size-4)}
.blog .u-col-6{max-width:var(--col-size-6)}
.blog .u-col-8{max-width:var(--col-size-8)}
.blog .u-align-end{justify-content:flex-end;align-items:center;display:flex}
.blog .u-color-dark-40{color:var(--color--dark-40)}
.blog .spacer{padding:0}
.blog .spacer[data-wf--spacer--variant="160"]{height:var(--space-l)}
.blog .spacer[data-wf--spacer--variant="32"]{height:var(--space-sm)}
.blog .spacer[data-wf--spacer--variant="16"]{height:var(--space-s)}
@media (max-width:767px){
  .blog .u-col-sm-3{max-width:var(--col-size-3)}
  .blog .u-col-sm-5,.blog .u-col-6,.blog .u-col-8,.blog .u-col-sm-8{min-width:100%;max-width:var(--col-size-5)}
  .blog .row.u-sm-last{order:9999}
  .blog .u-hide-sm{display:none}
  .blog .spacer[data-sm="120"]{height:var(--space-m)}
}

/* -------------------------------------------------------------- 3. type */
.blog h1,.blog .h-xl,.blog .h-l{font-family:var(--font-display);font-weight:600;margin:0;color:inherit}
.blog h1{font-size:12.5em;line-height:.8;letter-spacing:-.05em;padding-bottom:.1em}
/* Adapt: .1em under the list h1 — the reference's "News" has no descender, our "Blog" g
   at line-height .8 otherwise reaches the first item's hairline (measured 6px overlap at 1440). */
/* (0,2,0) beats .blog h1's (0,1,1), so the article's <h1 class="h-xl"> is 8em */
/* Adapt: .9, not the reference's .8 — at .8 Chrome paints the next line over the
   previous line's descenders (p, g, y) and our titles have them; .9 is the tightest
   value that keeps them intact (measured against .8/.85/.9/.95/1). */
.blog .h-xl{font-size:8em;line-height:.9;letter-spacing:-.05em}
.blog .h-l{font-size:3em;line-height:.9;letter-spacing:-.02em}
.blog .p-l{font-size:1.125em;margin:0}
.blog p{margin:0}
@media (max-width:767px){
  .blog h1{font-size:3em}
  .blog .h-xl{font-size:2.5em}
  .blog .h-l{font-size:1.5em}
}

/* ------------------------------------------------------------- 4. media */
.blog .media-w{z-index:1;background-color:var(--color--dark-20);width:100%;height:100%;position:relative;overflow:hidden}
.blog .media-inner{width:100%;height:114%;position:absolute;top:0;left:0;will-change:transform}
.blog .img{object-fit:cover;width:100%;height:100%;max-width:none;display:block}

/* --------------------------------------------------------- 5. news list */
.blog .news-list{flex-flow:column;display:flex}
.blog .news-item__inner{width:100%;display:block;color:inherit;text-decoration:none}
.blog .news-item__visual{aspect-ratio:1 / 1.1;width:100%;overflow:hidden}
.blog .news-item__inner-content{height:100%;padding-top:var(--gap-s);padding-bottom:var(--gap-ml);border-top:1px solid var(--color--dark);width:calc(100% + 2 * var(--col-pad));margin-left:calc(-2 * var(--col-pad));padding-left:calc(2 * var(--col-pad));flex-flow:column;justify-content:space-between;align-items:stretch;display:flex}
/* Adapt: the reference lets the date wrap; between 768 and 900 the 2-col date
   box is narrow enough to break "22 / February / 2022" onto three lines.
   Keeping it on one line then overruns the 2-col box (104px of text in 98px at
   768), so in that band only the date column is widened to a 3-col — the icon
   column is flex:1 and absorbs it, and no measured value at 1440 or 390 moves. */
.blog .news-item time{white-space:nowrap}
@media (min-width:768px) and (max-width:991px){
  .blog .news-item__inner-content .u-col-sm-3{max-width:var(--col-size-3)}
}
.blog .news-item__icon-w{justify-content:flex-end;align-items:center;width:3.75em;display:flex;overflow:hidden}
.blog .icon-w{flex:none;width:3.75em}
.blog .icon{justify-content:center;align-items:center;width:100%;display:flex}
.blog .icon .svg{width:100%;height:auto;display:block}
.blog .news-item__inner .icon-w,.blog .news-item__inner .media-w{transition:transform var(--animation-default)}
@media (hover:hover){
  .blog .news-item__inner:hover .icon-w{transform:translate(100%)}
  .blog .news-item__inner:hover .media-w{transform:scale(1.08)}
}
@media (max-width:767px){
  .blog .news-list{gap:4.5em}
  .blog .news-item__visual{aspect-ratio:1.5}
  .blog .news-item__inner-content{gap:var(--gap-l);border-top-style:none;width:100%;margin-left:0;padding-left:0}
}

/* ------------------------------------------------------------ 6. article */
.blog .news-header__eyebrow{z-index:2;margin-bottom:var(--gap-s);position:relative}
.blog .text-link{padding-top:.05em;padding-bottom:.05em;display:inline-block;overflow:clip;font-size:1em;color:inherit;text-decoration:none}
.blog .text-link:focus-visible{text-decoration:underline;text-underline-offset:.15em}
@media (hover:hover){.blog .text-link:hover{text-decoration:underline;text-underline-offset:.15em}}
.blog .article-hero .media-w{aspect-ratio:1.5 / 1;height:auto}
.blog .news-intro__specs{justify-content:space-between;align-items:center;width:100%;display:flex}
/* The reference's `.article h2{float:right;max-width:calc(50% - 2*col-pad)}`
   is dropped: its one article had no subheads, so the rule was never
   exercised — with ours it parks every h2 ~300px from the copy it heads. */
.blog .article h2{clear:both;max-width:42%;margin:1.5em 0 .5em;font:600 1.5em/1.1 var(--font-display);letter-spacing:-.02em}
.blog .article h3{clear:both;font:600 1.25em/1.2 var(--font-display);letter-spacing:-.02em;max-width:42%;margin:0 0 .75em}
.blog .article p{clear:both;width:100%;max-width:42%;font-size:1.25em;line-height:1.6;margin:0 0 1.25em}
.blog .article ul,.blog .article ol{clear:both;max-width:42%;font-size:1.25em;line-height:1.6;margin:0 0 1.25em;padding-left:1.25em}
.blog .article a{color:inherit;text-decoration:underline;text-underline-offset:.15em}
@media (max-width:767px){
  .blog .article h2{max-width:100%;margin:2.5em 0 .75em}
  .blog .article h3,.blog .article p,.blog .article ul,.blog .article ol{max-width:100%}
}

/* ------------------------------------------------------- 7. load reveal
   Static CSS shows everything; site/js/blog.js adds .js-reveal FIRST (hides
   the words + first images) and .is-in a frame later (plays them). Words:
   yPercent 140 + rotate 5deg -> 0 in .7s, stagger .03s from .1s; images:
   opacity 0 -> 1 in .4s from .5s. Reduced motion: no transitions at all. */
/* The mask must be taller than the .8 line box or descenders (g, p, y) and
   the tallest ascenders are clipped: padding gives the glyphs room, the equal
   negative margin keeps the line box exactly where it was. */
.blog .word-mask{display:inline-block;overflow:hidden;vertical-align:top;padding:.14em .05em .3em;margin:-.14em -.05em -.3em}
.blog .word{display:inline-block;transform-origin:left bottom}
.blog.js-reveal .word{transform:translateY(140%) rotate(5deg)}
.blog.js-reveal .reveal-img{opacity:0}
.blog.js-reveal.is-in .word{transform:none;transition:transform .7s var(--cubic-default);transition-delay:calc(.1s + var(--i,0) * .03s)}
.blog.js-reveal.is-in .reveal-img{opacity:1;transition:opacity .4s ease;transition-delay:.5s}
@media (prefers-reduced-motion:reduce){
  .blog .news-item__inner .icon-w,.blog .news-item__inner .media-w,.blog.js-reveal.is-in .word,.blog.js-reveal.is-in .reveal-img{transition:none}
  .blog.js-reveal .word{transform:none}
  .blog.js-reveal .reveal-img{opacity:1}
}
