/* ==========================================================================
   /blog — build log
   Hand-maintained. Loaded AFTER /style.css, which supplies every piece of site
   chrome (masthead, nav, footer, tokens, .btn). Nothing here is generated;
   build-blog.mjs only stamps this file's content hash into the ?v= of the
   pages it writes, because /blog/* is served with a long browser cache.
   Reference canvases: 1280 desktop, 390 mobile, same 900px breakpoint.
   ========================================================================== */

/* The masthead caps the top of a rounded card; these close the bottom of it,
   exactly like .hero on page 1 and .so on /solidout. */
.blogpage,
.post{
  margin:0 var(--pad-x) var(--frame-gap);
  padding:34px 40px 40px;
  background:var(--ink-plum);
  border-radius:0 0 var(--r-lg) var(--r-lg);
}

/* ---------- index ---------- */

.blogpage__head{
  padding-bottom:22px;margin-bottom:26px;
  border-bottom:1px solid var(--rule-soft);
}
.blogpage__h1{
  margin:0;
  font:800 42px/1.05 var(--sans);letter-spacing:-.035em;color:var(--cream);
}
.blogpage__lede{
  margin:12px 0 0;max-width:62ch;
  font:400 15.5px/1.55 var(--sans);color:var(--cream-70);
}
.blogpage__lede a{color:var(--amber)}

/* One column of wide rows. A build log is read newest-first, not browsed as a
   grid of thumbnails, so the row gives the summary real width. */
.plist{display:flex;flex-direction:column;gap:12px}
.plist__row{
  display:grid;grid-template-columns:1fr auto;grid-template-areas:
    "meta  meta"
    "title title"
    "sum   go";
  gap:6px 20px;align-items:end;
  padding:20px 22px;
  border:1px solid var(--rule);border-radius:var(--r-sm);
  color:var(--cream);
  transition:background .16s ease,border-color .16s ease;
}
.plist__row:hover{background:rgba(253,246,236,.06);border-color:var(--rule-strong);color:var(--cream)}
.plist__meta{
  grid-area:meta;
  font:400 10.5px var(--mono);letter-spacing:.16em;text-transform:uppercase;
  color:var(--cream-45);
}
.plist__tag{color:var(--amber)}
.plist__tag::before{content:'· '; color:var(--cream-35)}
.plist__title{
  grid-area:title;
  font:700 23px/1.25 var(--sans);letter-spacing:-.02em;color:var(--cream);
}
.plist__sum{
  grid-area:sum;max-width:74ch;
  font:400 14.5px/1.5 var(--sans);color:var(--cream-62);
}
.plist__go{
  grid-area:go;white-space:nowrap;
  font:600 11px var(--mono);letter-spacing:.12em;text-transform:uppercase;
  color:var(--amber);
}

/* ---------- post ---------- */

.post{max-width:none}

/* The header picture. A cap is mandatory: a portrait screenshot at natural
   size pushes the title off the fold entirely. Cropped from the top, which is
   where the useful part of a UI shot lives. */
.post__cover{
  margin:0 0 28px;
  max-height:380px;overflow:hidden;
  border:1px solid var(--rule-soft);border-radius:var(--r-sm);
  background:var(--ink-deep);
}
.post__cover img{display:block;width:100%;height:auto;object-fit:cover;object-position:center top}
.post__head{
  padding-bottom:24px;margin-bottom:30px;
  border-bottom:1px solid var(--rule-soft);
}
.post__meta{
  font:400 10.5px var(--mono);letter-spacing:.16em;text-transform:uppercase;
  color:var(--cream-45);
}
.post__h1{
  margin:12px 0 0;max-width:22ch;
  font:800 46px/1.04 var(--sans);letter-spacing:-.035em;color:var(--cream);
}
.post__lede{
  margin:16px 0 0;max-width:64ch;
  font:400 18px/1.5 var(--sans);color:var(--cream-82);
}

/* The reading column. 68ch is ~72 characters at this size — long enough for a
   code line to breathe, short enough that the eye finds the next line. */
.post__body{max-width:68ch;color:var(--cream-82);font:400 17px/1.68 var(--sans)}
.post__body > *:first-child{margin-top:0}
.post__body p{margin:0 0 1.15em}
.post__body h2{
  margin:2em 0 .6em;
  font:700 27px/1.2 var(--sans);letter-spacing:-.025em;color:var(--cream);
}
.post__body h3{
  margin:1.8em 0 .5em;
  font:700 20px/1.3 var(--sans);letter-spacing:-.015em;color:var(--cream);
}
.post__body h4{
  margin:1.6em 0 .4em;
  font:600 12px var(--mono);letter-spacing:.14em;text-transform:uppercase;color:var(--amber);
}
.post__body a{color:var(--coral);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:rgba(242,116,62,.45)}
.post__body a:hover{color:var(--amber);text-decoration-color:var(--amber)}
.post__body a .ext{text-decoration:none;font-size:.85em}
.post__body strong{color:var(--cream);font-weight:700}
.post__body ul,.post__body ol{margin:0 0 1.15em;padding-left:1.35em}
.post__body li{margin:0 0 .45em}
.post__body li::marker{color:var(--cream-35)}
.post__body hr{
  margin:2.2em 0;border:0;border-top:1px solid var(--rule-soft);
}

.post__body blockquote{
  margin:1.6em 0;padding:2px 0 2px 20px;
  border-left:2px solid var(--amber);
  color:var(--cream-70);font-style:italic;
}
.post__body blockquote p:last-child{margin-bottom:0}

/* Inline code and fenced blocks share the mono ramp; the block scrolls inside
   itself so a long line can never widen the page. */
.post__body code{
  font:400 .88em var(--mono);
  padding:.12em .34em;border-radius:4px;
  background:rgba(253,246,236,.08);color:var(--cream);
}
.post__body pre.code{
  margin:1.5em 0;padding:16px 18px;
  background:var(--ink-deep);border:1px solid var(--rule-soft);border-radius:var(--r-sm);
  overflow-x:auto;
}
.post__body pre.code code{
  padding:0;background:none;
  font:400 13.5px/1.6 var(--mono);color:var(--cream-82);white-space:pre;
}
.post__body pre.code[data-lang]::before{
  content:attr(data-lang);display:block;margin-bottom:10px;
  font:600 9.5px var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--cream-35);
}

.post__body figure{margin:1.8em 0}
.post__body img{display:block;width:100%;height:auto;border-radius:var(--r-sm)}
.post__body figcaption{
  margin-top:9px;
  font:400 11.5px/1.5 var(--mono);color:var(--cream-45);
}

/* ---------- canvas posts (@MakerBlog) ----------
   Blocks are placed as PERCENTAGES of a stage carrying the design canvas's
   aspect-ratio, so a free layout keeps its shape across desktop widths without
   a line of script. Below the breakpoint the stage stops positioning anything
   and becomes a flex column: each block goes full width, ordered by the inline
   `order` the generator writes from the document's reading order. Percentages
   cannot rescue an absolute layout at 390px — the text inside does not shrink
   with the box — so it stacks instead of squeezing. */

.post__body--canvas{max-width:none;font-size:inherit}
/* container-type makes cqw mean "1% of this stage's width", which is how the
   wrap spacers stay locked to the pictures they stand in for at every window
   size. inline-size only — a size container would need a fixed height. */
.cv{position:relative;width:100%;container-type:inline-size}
.cvb{position:absolute;margin:0}

.cvb--image img{display:block;width:100%;height:100%}
.cvb--image figcaption{
  margin-top:8px;
  font:400 11.5px/1.5 var(--mono);color:var(--cream-45);
}
.cvb--divider{display:flex;align-items:center}
.cvb--divider span{display:block;width:100%;height:1px;background:var(--rule-soft)}

/* Text wrap. An empty floated box reserving the rectangle a picture occupies;
   the text flows around it because that is what floats do. The picture itself
   is a separate absolutely positioned block sitting on top — the spacer only
   holds the space open. */
.cvwrap{display:block;pointer-events:none}

.cvt{margin:0}
.cvt--h2{font:700 27px/1.2 var(--sans);letter-spacing:-.025em}
.cvt--h3{font:700 20px/1.3 var(--sans);letter-spacing:-.015em}
.cvt--label{font:600 12px/1.4 var(--mono);letter-spacing:.14em;text-transform:uppercase}
.cvt--body{font:400 17px/1.68 var(--sans)}
.cvt--lede{font:400 18px/1.5 var(--sans)}
.cvt--quote{font:400 italic 17px/1.6 var(--sans)}
.cvt--caption{font:400 11.5px/1.5 var(--mono)}
.cvt--code{font:400 13.5px/1.6 var(--mono);white-space:pre-wrap}
.cvt code{
  font:400 .88em var(--mono);padding:.12em .34em;border-radius:4px;
  background:rgba(253,246,236,.08);
}
.cvt a{color:var(--coral);text-decoration:underline;text-underline-offset:3px}
.cvt a:hover{color:var(--amber)}

@media (max-width:900px){
  /* No flex gap: spacing is per block (margin-bottom, set in the editor's
     phone pane) so one block can breathe without moving every other one. The
     20px here is the fallback for a document written before that existed. */
  .cv{
    aspect-ratio:auto !important;
    display:flex;flex-direction:column;gap:0;
  }
  .cvb{
    position:static !important;
    left:auto !important;top:auto !important;
    width:100% !important;height:auto !important;
    margin-bottom:20px;
  }
  .cvb:last-child{margin-bottom:0}
  /* Set on the block itself in the phone pane: taken off phones entirely, or
     pinned to a chosen height (pictures only — text rewraps and a fixed height
     could only clip it). */
  .cvb--nophone{display:none !important}
  /* The height pins the PICTURE, not the figure: a figure also holds the
     caption, and pinning the whole box pushed the caption out of it and on
     top of the next block. */
  .cvb--phfix{height:auto !important}
  .cvb--phfix img{height:var(--ph);object-fit:cover}
  .cvb--image img{height:auto}
  /* Stacked one per row, nothing overlaps anything, so there is nothing to
     flow around and a leftover float would only eat the first line. */
  .cvwrap{display:none !important}
  .cvt--h2{font-size:21px}
  .cvt--h3{font-size:17.5px}
  .cvt--body,.cvt--lede{font-size:16px;line-height:1.62}
}

/* ---------- prev / next ---------- */

.pnav{
  display:grid;grid-template-columns:1fr 1fr;gap:12px;
  margin-top:44px;padding-top:26px;
  border-top:1px solid var(--rule-soft);
}
.pnav__link{
  display:flex;flex-direction:column;gap:6px;
  padding:16px 18px;
  border:1px solid var(--rule);border-radius:var(--r-sm);
  color:var(--cream);
  transition:background .16s ease,border-color .16s ease;
}
.pnav__link:hover{background:rgba(253,246,236,.06);border-color:var(--rule-strong);color:var(--cream)}
.pnav__link--r{align-items:flex-end;text-align:right}
.pnav__dir{
  font:600 10px var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--amber);
}
.pnav__t{font:600 15px/1.35 var(--sans);color:var(--cream-82)}

.post__back{
  margin:22px 0 0;
  font:600 11.5px var(--mono);letter-spacing:.1em;text-transform:uppercase;
}
.post__back a{color:var(--cream-62)}
.post__back a:hover{color:var(--amber)}

/* ---------- mobile ---------- */

@media (max-width:900px){
  .blogpage,.post{padding:22px 18px 26px}
  .post__cover{margin-bottom:20px;max-height:220px}

  /* A post slug makes the masthead prompt long enough to wrap onto a second
     line and push the lockup down. One line, clipped. */
  .brand__prompt{
    display:block;max-width:60vw;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }

  .blogpage__h1{font-size:30px}
  .blogpage__lede{margin-top:9px;font-size:14px}
  .blogpage__head{padding-bottom:16px;margin-bottom:18px}

  /* The "Read" chip stops competing with the summary for the same row. */
  .plist__row{
    grid-template-columns:1fr;grid-template-areas:"meta" "title" "sum" "go";
    align-items:start;gap:7px;padding:16px 15px;
  }
  .plist__title{font-size:19px}
  .plist__sum{font-size:13.5px}
  .plist__go{margin-top:2px}

  .post__h1{font-size:29px;max-width:none}
  .post__lede{margin-top:12px;font-size:15.5px}
  .post__head{padding-bottom:18px;margin-bottom:22px}
  .post__body{font-size:16px;line-height:1.62;max-width:none}
  .post__body h2{margin-top:1.7em;font-size:21px}
  .post__body h3{font-size:17.5px}
  .post__body pre.code{padding:13px 14px}
  .post__body pre.code code{font-size:12.5px}

  .pnav{grid-template-columns:1fr;margin-top:32px;padding-top:20px}
  .pnav__link--r{align-items:flex-start;text-align:left}
}
