/* ==========================================================================
   BLOG — the index shelf and the article page, in one file.

   Both live under /blog and share the header band and the crumb, so they are
   one stylesheet rather than two <style> blocks that drift apart. Load it
   AFTER /css/system.css:

     <link rel="stylesheet" href="/css/system.css">
     <link rel="stylesheet" href="/css/blog.css">

   Tokens, type, buttons, .sec, .cta, the footer and the nav component all come
   from system.css. Nothing here redefines them, and there are no hardcoded
   colour values in this file.
   ========================================================================== */

/* clip, not hidden — overflow:hidden on <body> makes it a scroll container
   and silently kills position:sticky on the header. */
body{overflow-x:clip}

/* ---- SHARED HEADER -------------------------------------------------------
   Same band on the index and on a post. On a post it carries the crumb and
   the meta line; on the index it carries the lede.                          */
.blog-top{padding:clamp(40px,4.6vw,68px) 0 clamp(30px,3.4vw,46px)}
.blog-top h1{max-width:20ch}
.blog-top .lede{max-width:62ch;margin-top:20px}

.crumb{
  display:flex;flex-wrap:wrap;align-items:center;gap:9px;margin-bottom:22px;
  font-weight:700;font-size:11px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--sand-3);
}
.crumb a{color:var(--sand-2);text-decoration:none}
.crumb a:hover{color:var(--sand);text-decoration:underline}
/* On a phone the post title is long enough to wrap and strand the slash on
   its own line. Collapse to a plain back link — the h1 below says where you
   are already. */
@media (max-width:560px){
  .crumb span{display:none}
  .crumb a::before{content:"\2190";margin-right:9px}
}

/* ---- SHARED META LINE ----------------------------------------------------
   Date and read-time, with a hairline icon in front of each. The icons are
   mask-images rather than inline <svg> so the colour comes from the cascade
   (currentColor) and the markup stays legible — this line appears on the
   featured card and on every one of the cards below it.                     */
.pmeta{
  display:flex;flex-wrap:wrap;align-items:center;gap:7px 18px;margin:0;
  font-weight:700;font-size:12px;letter-spacing:.06em;
  color:var(--sand-3);
}
.pmeta span{display:inline-flex;align-items:center;gap:7px}
.pmeta span::before{
  content:"";flex:0 0 auto;width:14px;height:14px;
  background:currentColor;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
}
.pmeta .m-date::before{
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Crect x='3' y='5' width='18' height='16' rx='2'/%3E%3Cpath d='M8 3v4M16 3v4M3 10h18'/%3E%3C/svg%3E");
          mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Crect x='3' y='5' width='18' height='16' rx='2'/%3E%3Cpath d='M8 3v4M16 3v4M3 10h18'/%3E%3C/svg%3E");
}
.pmeta .m-read::before{
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5.2l3.1 1.9'/%3E%3C/svg%3E");
          mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5.2l3.1 1.9'/%3E%3C/svg%3E");
}

/* ---- FEATURED ------------------------------------------------------------
   The newest post, given a whole band — full-bleed, with no frame around it.
   That is what makes it outrank the six cards below: it is not a bigger card
   competing with smaller cards, it is a different kind of object entirely.
   Putting a border back on it turns it into the largest item in a set instead
   of the thing the set hangs under, which is a much weaker signal.

   The band is `.photo-hero .hero-card` now — the same cream photographic hero
   that opens /hvac, /roofing, /work, /courses and /resources, defined in
   system.css. It used to be a dark band that faded into the list below over a
   144px runway of bottom padding; the card's edge does that job now, and does
   it the way the rest of the site does it, so the ground, the photograph, the
   scrim and the padding all come from the component. Do not restate any of
   them here: this file loads after system.css at equal specificity and a
   `padding` shorthand would silently eat the component's.

   What is left below is only the content row, and the part of it that has to
   be re-pointed because the ground went from near-black to cream.

   Not an <a>. The "Read More" pill would be a link inside a link, which is
   invalid; instead the headline's anchor is stretched over the whole row with
   ::after and the pill is a decorative span.                                */
/* The crop the band used before it became a component, kept. */
.blog-feat{--hero-pos-w:50% 42%}

/* .photo-hero-in caps its children at 600px so copy stays off the picture.
   That cap is wrong for this one page: the child here is not a paragraph, it
   is a 2-up row with the Read More pill on the far right, and capping the ROW
   drags the pill into the middle of the band. Release the row and move the cap
   onto the column that actually holds the reading, which is what the cap was
   protecting in the first place. 600px of copy ends around x=730 and the
   photograph's mask keeps it invisible until roughly x=900, so the clear third
   still holds. */
.feat{
  position:relative;
  display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;
  gap:22px clamp(24px,3.4vw,48px);
}
@media (min-width:940px){
  .blog-feat .photo-hero-in>*{max-width:none}
  .feat-copy{max-width:min(100%,600px)}
}
.feat-copy{flex:1 1 440px;min-width:0}
/* Says what the band is without a headline above it having to.

   --accent is the warm tan that carried this on the old near-black ground. On
   cream it measures 1.6:1 and the pill disappears, so the whole chip re-points
   to --ox: a 12% tint, a half-strength rule and solid oxblood lettering. Same
   object, same weight in the layout, legible on the surface it is now on. */
/* Compound, not a lone `.feat-tag`. This element is a <p>, and the component's
   `.photo-hero p` rule is (0,1,1) — it beats a bare class no matter which file
   loads later, and the chip silently comes out in body colour. */
.blog-feat .feat-tag{
  display:inline-block;margin:0 0 clamp(16px,1.8vw,22px);
  padding:7px 15px;border-radius:999px;
  background:color-mix(in srgb,var(--ox) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--ox) 46%,transparent);
  color:var(--ox);
  font-weight:800;font-size:11px;letter-spacing:.16em;text-transform:uppercase;
}
/* --sand-2 is a translucent cream and vanishes here. --ink-3 is the muted end
   of the light-ground ramp and is what .cta uses for the same job. */
.feat .pmeta{color:var(--ink-3)}
.feat h1{
  margin:.5em 0 .42em;max-width:19ch;
  font-weight:900;letter-spacing:-.034em;line-height:1.02;
  /* Roughly 2.8x the card headline at the top end. The gap has to be obvious
     at a glance or the band just looks like a card that got more room. */
  font-size:clamp(32px,4.4vw,56px);
}
.feat h1 a{
  color:inherit;text-decoration:none;
  transition:color .2s var(--ease);
}
/* Stretched hit area. z-index keeps it above the two decorative layers but it
   is still behind nothing else — there is no other interactive child. */
.feat h1 a::after{content:"";position:absolute;z-index:1;inset:0}
/* Hover went to --accent, which was the lift on a dark ground. On cream the
   only direction left is down, so it darkens instead. */
.feat:hover h1 a{color:var(--ox-deep)}
.feat p{margin:0;max-width:56ch;font-size:16.5px;line-height:1.62;color:var(--ink-2)}
/* The pill is a span, so it has no :hover of its own — the whole row drives
   it, which is also the honest signal since the whole row is clickable.

   The resting state is .photo-hero .btn, an --ox fill. This has to beat it,
   and .photo-hero .btn is (0,2,0) while .feat:hover .feat-btn is (0,3,0), so
   it does. It matches .photo-hero .btn:hover on purpose — the whole row
   hovering should look exactly like the button hovering. */
.feat-btn{flex:0 0 auto;align-self:flex-end}
.feat:hover .feat-btn{background:var(--ox-deep);border-color:var(--ox-deep)}
@media (max-width:700px){
  .feat{display:block}
  .feat-btn{margin-top:24px}
}

/* ---- FILTER CHIPS --------------------------------------------------------
   Plain buttons, not a <select>. Five of them fit on one line at desktop and
   wrap to two on a phone, which is cheaper to scan than opening a menu.
   Behaviour: /js/blog.js. With JS off every card stays visible, which is the
   correct fallback for a filter.                                            */
.chips{
  display:flex;flex-wrap:wrap;gap:9px;
  padding:0 0 clamp(20px,2.4vw,30px);
}
.chip{
  appearance:none;cursor:pointer;
  padding:9px 17px;border-radius:999px;
  border:1px solid var(--line);
  background:color-mix(in srgb,var(--sand) 6%,transparent);
  color:var(--sand-2);
  font-family:inherit;font-weight:700;font-size:12.5px;letter-spacing:.04em;
  transition:background .2s var(--ease),color .2s var(--ease),border-color .2s var(--ease);
}
.chip:hover{background:color-mix(in srgb,var(--sand) 12%,transparent);color:var(--sand)}
.chip[aria-pressed="true"]{
  background:var(--accent);border-color:var(--accent);color:var(--ink);
}

/* ---- CARD GRID -----------------------------------------------------------
   Three up. The whole card is the link, so the inner wrapper is a <div> —
   a <span> cannot legally hold the <h3> and <p>.                            */
/* No top padding worth the name: the band above ends in a fade that already
   reads as space. Adding a normal section gap here reopens the seam the fade
   was there to close. */
.blog-list{padding:clamp(6px,1vw,14px) 0 clamp(44px,4.2vw,72px)}
/* Same restatement the tab row needs on /resources: this band is the
   .hero-join under the raised hero card and it sets its own top padding, which
   beats .hero-join's calc because blog.css loads later at equal specificity.
   Its own padding is nearly nothing on purpose (see the note above), so here it
   is essentially just the radius being put back. */
.blog-list.hero-join{
  padding-top:calc(clamp(6px,1vw,14px) + clamp(20px,2.6vw,38px));
}
.cards{
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(16px,2vw,26px);
  list-style:none;margin:0;padding:0;
}
@media (max-width:940px){.cards{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:620px){.cards{grid-template-columns:1fr;max-width:520px}}

/* [hidden] loses to display:flex, so it has to be restated here. This is what
   js/blog.js toggles for both the chip filter and the show-more cap. */
.card[hidden]{display:none}

.card{
  display:flex;flex-direction:column;
  text-decoration:none;color:inherit;
  background:linear-gradient(176deg,var(--ox-2),var(--brown-2));
  border:1px solid var(--line);
  box-shadow:0 22px 44px -30px var(--ox-deep);
  transition:border-color .3s var(--ease),transform .3s var(--ease),box-shadow .3s var(--ease);
}
.card:hover{
  border-color:color-mix(in srgb,var(--accent) 62%,transparent);
  transform:translateY(-4px);
  box-shadow:0 36px 64px -30px var(--ox-deep);
}

/* FILLER ART — TEMPORARY. Same drawn contour plate the homepage post cards
   use. When real photography exists, swap <span class="card-art"> for an
   <img> at the same 16/10 ratio and keep the badge where it is. */
.card-art{
  position:relative;display:block;aspect-ratio:16/10;overflow:hidden;
  background:
    radial-gradient(98% 124% at 16% 0%,color-mix(in srgb,var(--accent) 19%,transparent),transparent 66%),
    linear-gradient(150deg,var(--ox-2),var(--ox-deep));
  border-bottom:1px solid var(--line);
}
.card-art::before{
  content:"";position:absolute;inset:-20% -12%;
  background:url(/assets/topo.svg) center/cover no-repeat;
  opacity:.32;transition:transform .55s var(--ease);
}
/* Offset the contour per card so six cards are not six copies of one picture.
   nth-child(3n) cycling means the pattern also holds after a filter reflows
   which cards are adjacent. */
.card:nth-child(3n+2) .card-art::before{background-position:20% 74%}
.card:nth-child(3n) .card-art::before{background-position:80% 28%}
.card:hover .card-art::before{transform:scale(1.08)}

/* Real photograph in the same slot. The <img> goes INSIDE the existing
   .card-art span rather than replacing it, because the badge is positioned
   against that span and an <img> cannot carry a child. The span keeps the
   16/10 ratio and the clipping; the photo just fills it.

   .has-img kills the contour plate underneath. Leaving it on costs a paint of
   a texture nobody can see through an opaque photo, and it would show at the
   edges for the moment before the image decodes. */
.card-art.has-img::before{display:none}
.card-art img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform .55s var(--ease);
}
.card:hover .card-art img{transform:scale(1.05)}
/* The badge is sand on ink and sits on whatever the photo happens to be doing
   in that corner, so it gets its own shadow rather than relying on the picture
   being dark there. */
.card-art.has-img .card-badge{box-shadow:0 2px 10px rgba(0,0,0,.45)}
@media (prefers-reduced-motion:reduce){
  .card-art img{transition:none}
  .card:hover .card-art img{transform:none}
}

.card-badge{
  position:absolute;right:12px;bottom:12px;
  padding:6px 12px;border-radius:999px;
  background:var(--sand);color:var(--ink);
  font-weight:800;font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
}

.card-body{display:flex;flex-direction:column;flex:1;padding:clamp(18px,2vw,24px)}
.card .pmeta{margin-bottom:13px}
.card h3{
  font-size:clamp(17px,1.6vw,20px);line-height:1.25;margin:0 0 .5em;
  transition:color .2s var(--ease);
}
.card:hover h3{color:var(--accent)}
/* Clamped to three lines. Uneven excerpt lengths are what make a card grid
   look like a junk drawer; the clamp gives every card the same shape and the
   browser supplies the ellipsis.

   No flex:1 here. As a flex item the paragraph would be stretched to the
   leftover space and then clipped by its own overflow:hidden — which cuts the
   copy mid-line with no ellipsis, because the clamp never ran. The margin-top
   on .go does the pushing instead. */
.card p{
  margin:0;font-size:14.5px;line-height:1.55;color:var(--sand-2);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden;
}
.card .go{margin-top:auto;padding-top:18px;color:var(--accent);font-weight:700;font-size:13px;letter-spacing:.03em}

@media (prefers-reduced-motion:reduce){
  .card,.card-art::before{transition:none}
  .card:hover{transform:none}
  .card:hover .card-art::before{transform:none}
}

/* ---- SHOW MORE -----------------------------------------------------------
   Hidden until js/blog.js decides there is something left to reveal, so it
   never sits there promising posts that do not exist.                       */
.more-wrap{display:flex;justify-content:center;margin-top:clamp(26px,3vw,38px)}
.more-wrap[hidden]{display:none}

.blog-empty{margin:clamp(26px,3vw,38px) 0 0;text-align:center;color:var(--sand-2)}
.blog-empty[hidden]{display:none}

/* ---- ARTICLE -------------------------------------------------------------
   A single measured column. Nothing sits beside the prose — a sidebar on a
   page whose whole job is to be read is just something else to look at.     */
.art-meta{
  display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:0 0 18px;
  font-weight:700;font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--sand-3);
}
.art-meta b{color:var(--accent);font-weight:800}

/* The post header and the prose share one 760px column. Leaving the header on
   the full 1180 wrap put the h1 hard left and the body indented ~210px under
   it, which reads as two different pages stacked. */
.art-head .wrap,
.art .wrap{max-width:760px}
.art{padding:0 0 clamp(44px,4.2vw,72px)}

.art h2{
  font-size:clamp(22px,2.3vw,30px);line-height:1.15;
  margin:clamp(34px,3.6vw,50px) 0 .5em;
}
.art h3{font-size:clamp(18px,1.7vw,21px);margin:clamp(26px,2.6vw,34px) 0 .5em}
.art p{margin:0 0 1.15em;font-size:16.5px;line-height:1.72;color:var(--sand-2)}
.art p strong{color:var(--sand);font-weight:700}

.art ul,.art ol{margin:0 0 1.35em;padding-left:1.25em;color:var(--sand-2)}
.art li{margin-bottom:.6em;font-size:16.5px;line-height:1.7}
.art li::marker{color:var(--accent)}
.art li strong{color:var(--sand);font-weight:700}

/* These posts quote real URLs and file names, which wrap badly and get
   mistaken for prose without a tint behind them. */
.art code{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:.86em;padding:2px 6px;border-radius:4px;
  background:color-mix(in srgb,var(--sand) 11%,transparent);
  color:var(--sand);overflow-wrap:anywhere;
}

/* Pull quote. A rule above and below rather than a left bar — the site does
   not use left accent stripes anywhere, and this is the one element tempted
   to introduce one. */
.art blockquote{
  margin:clamp(26px,3vw,38px) 0;padding:clamp(18px,2vw,24px) 0;
  border-top:1px solid color-mix(in srgb,var(--accent) 34%,transparent);
  border-bottom:1px solid color-mix(in srgb,var(--accent) 34%,transparent);
  font-weight:700;letter-spacing:-.01em;line-height:1.3;
  font-size:clamp(18px,1.9vw,23px);color:var(--sand);
}
.art blockquote p{margin:0;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}

/* The "how to check this yourself" box. One per post, so it is a panel rather
   than a repeated card. */
.art-box{
  margin:clamp(28px,3vw,40px) 0;padding:clamp(20px,2.2vw,28px);
  background:var(--ox-2);border:1px solid color-mix(in srgb,var(--accent) 34%,transparent);
}
.art-box h3{margin-top:0}
.art-box :last-child{margin-bottom:0}

.art-sign{
  margin-top:clamp(30px,3.4vw,44px);padding-top:clamp(18px,2vw,24px);
  border-top:1px solid var(--line);
  font-size:13.5px;color:var(--sand-3);
}
