/*
Theme Name: Triple Zero Labs 2026
Theme URI: https://triplezero.xyz/
Author: Triple Zero Labs
Author URI: https://triplezero.xyz/
Description: Monochrome block theme for the Triple Zero Labs blog. Carries the
  landing-page design system — bold fluid typography, a two-value palette, film
  grain, and reveal-on-scroll — into WordPress.
Requires at least: 6.5
Tested up to: 7.0
Requires PHP: 8.0
Version: 1.4.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: triplezero2026
Tags: blog, one-column, block-patterns, full-site-editing, editor-style
*/

/* ==========================================================================
   Triple Zero Labs — WordPress theme
   Ported from the V2 landing page. Tokens, nav, footer, buttons and the
   reveal system are kept byte-compatible with styles.css so the two
   properties read as one brand; everything below BLOG is new.

   theme.json owns the palette, type scale and layout widths — it emits them
   as --wp--preset--* custom properties. The --tz-* tokens here are the
   authored names the components actually use, aliased to those presets so a
   change in theme.json flows through both the site and the block editor.
   ========================================================================== */

:root{
  /* monochrome ramp */
  --black: #0B0B0C;
  --white: #F4F4F5;

  --bg:    var(--wp--preset--color--base, #0B0B0C);
  --fg:    var(--wp--preset--color--contrast, #F4F4F5);
  --muted: var(--wp--preset--color--muted, rgba(244,244,245,.56));
  --faint: var(--wp--preset--color--faint, rgba(244,244,245,.34));
  --line:  var(--wp--preset--color--line, rgba(244,244,245,.14));
  --hair:  var(--wp--preset--color--hair, rgba(244,244,245,.08));

  /* type scale — fluid, no breakpoints needed */
  --t-xs:   clamp(.688rem, .66rem + .12vw, .75rem);
  --t-sm:   clamp(.813rem, .78rem + .16vw, .875rem);
  --t-base: clamp(1rem, .96rem + .22vw, 1.125rem);
  --t-lg:   clamp(1.125rem, 1.05rem + .4vw, 1.375rem);
  --t-xl:   clamp(1.5rem, 1.25rem + 1.1vw, 2.25rem);
  --t-h2:   clamp(2.25rem, 1.4rem + 3.9vw, 5.5rem);
  --t-hero: clamp(2.75rem, 1rem + 8.6vw, 9.5rem);

  /* rhythm */
  --gutter: clamp(1.25rem, 4vw, 4rem);
  --wrap:   1440px;
  /* Clearance for the fixed nav. Shared so the post hero can cancel it with a
     negative margin and sit behind the (transparent) nav instead. */
  --navpad: clamp(4.5rem, 7vw, 6rem);
  /* Measure for long-form body copy. Deliberately a fixed length rather than
     the more idiomatic 68ch: this is applied to every direct child of
     .tz-entry, and `ch` resolves against each element's own font — so code
     blocks came out ~250px narrower than the prose around them. A rem value
     gives every block the same column regardless of typeface. */
  --read:   48rem;
  /* Long-form body copy sits a step brighter than --muted. Reading a full
     article at the muted value is harder than scanning a caption at it. */
  --read-fg: rgba(244,244,245,.68);
  --sect:   clamp(4rem, 8vh + 3rem, 8rem);

  /* motion */
  --ease:    cubic-bezier(.22,1,.36,1);
  --ease-io: cubic-bezier(.65,0,.35,1);
}

/* Light mode. The landing page flips per-section via JS; a blog has no such
   choreography, so this is a whole-document switch driven by the toggle in
   the nav (and seeded from prefers-color-scheme on first visit).

   This overrides the *presets* rather than the --bg/--fg aliases above.
   theme.json's generated global-styles sheet loads after style.css and sets
   body{background-color:var(--wp--preset--color--base)} — overriding --bg
   alone leaves that rule pointing at the dark value and the page never
   flips. Repointing the presets moves everything downstream of them in one
   go: body, headings, links, buttons, and the aliases. */
html.tz-light{
  --wp--preset--color--base:     #F4F4F5;
  --wp--preset--color--contrast: #0B0B0C;
  --wp--preset--color--muted:    rgba(11,11,12,.62);
  --wp--preset--color--faint:    rgba(11,11,12,.38);
  --wp--preset--color--line:     rgba(11,11,12,.16);
  --wp--preset--color--hair:     rgba(11,11,12,.09);
  /* not preset-derived, so it needs its own light value */
  --read-fg: rgba(11,11,12,.74);
}

/* ---------- base ---------- */
html{ -webkit-text-size-adjust:100%; }

body{
  background:var(--bg);
  color:var(--fg);
  letter-spacing:-.011em;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
  transition:background-color .45s var(--ease-io), color .45s var(--ease-io);
}

img,svg{ display:block; max-width:100%; height:auto; }
a{ color:inherit; text-decoration:none; }

::selection{ background:var(--fg); color:var(--bg); }

:focus-visible{
  outline:2px solid var(--fg);
  outline-offset:4px;
  border-radius:2px;
}

/* WP drops .wp-site-blocks straight under body; give the fixed nav room. */
.wp-site-blocks{ padding-top:var(--navpad); }

/* ---------- scroll progress ---------- */
.progress{
  position:fixed; inset:0 0 auto 0;
  height:2px; z-index:120;
  pointer-events:none;
}
.progress__bar{
  display:block; height:100%; width:0%;
  background:var(--fg);
  transition:background-color .9s var(--ease-io);
}

/* ---------- film grain ---------- */
/* Kept at inset:0 — an oversized fixed box lets iOS Safari inflate the
   scrollable area, which shows up as dead space below the footer. */
.grain{
  position:fixed; inset:0;
  z-index:110;
  pointer-events:none;
  opacity:.035;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 6s steps(6) infinite;
}
@keyframes grain{
  0%,100%{ background-position:0 0; }
  20%{ background-position:-24px 16px; }
  40%{ background-position:16px -24px; }
  60%{ background-position:-16px -16px; }
  80%{ background-position:24px 8px; }
}

/* ==========================================================================
   NAV
   ========================================================================== */
/* Solid, not translucent. The post hero runs underneath the bar, and a light
   image behind a blurred panel left the nav unreadable — worse in dark mode,
   where the brand and links are near-white. Matching the page background keeps
   it legible over any image, in either scheme. */
.nav{
  position:fixed; top:0; left:0; right:0;
  z-index:100;
  gap:2rem;
  padding:1.35rem var(--gutter);
  background:var(--bg);
  border-bottom:1px solid transparent;
  transition:border-color .5s var(--ease), padding .5s var(--ease);
}
.nav.is-stuck{
  padding-block:.95rem;
  border-bottom-color:var(--hair);
}

.nav__brand{ display:flex; align-items:center; gap:.7rem; }
.nav__name{
  font-weight:700; font-size:var(--t-sm);
  letter-spacing:-.02em;
  white-space:nowrap;
}

/* the three zeros, as a mark */
.nav__mark{ display:flex; gap:3px; }
.nav__mark span{
  width:8px; height:8px; border-radius:50%;
  border:1.5px solid var(--fg);
  transition:transform .5s var(--ease), background-color .3s var(--ease);
}
/* The mark animates identically wherever it links out — nav or footer. */
.nav__brand:hover .nav__mark span,
.footer__brand-line:hover .nav__mark span{ background:var(--fg); }
.nav__brand:hover .nav__mark span:nth-child(1),
.footer__brand-line:hover .nav__mark span:nth-child(1){ transform:translateY(-3px); }
.nav__brand:hover .nav__mark span:nth-child(2),
.footer__brand-line:hover .nav__mark span:nth-child(2){ transform:translateY(-3px); transition-delay:.05s; }
.nav__brand:hover .nav__mark span:nth-child(3),
.footer__brand-line:hover .nav__mark span:nth-child(3){ transform:translateY(-3px); transition-delay:.1s; }

/* core/navigation, dressed to match the landing page's .nav__links */
.nav .wp-block-navigation{ font-size:var(--t-sm); }
.nav .wp-block-navigation .wp-block-navigation-item__content{
  color:var(--muted);
  position:relative; padding-block:.25rem;
  transition:color .35s var(--ease);
}
.nav .wp-block-navigation .wp-block-navigation-item__content::after{
  content:""; position:absolute; left:0; bottom:0;
  width:100%; height:1px; background:var(--fg);
  transform:scaleX(0); transform-origin:right;
  transition:transform .5s var(--ease);
}
.nav .wp-block-navigation .wp-block-navigation-item__content:hover{ color:var(--fg); }
.nav .wp-block-navigation .wp-block-navigation-item__content:hover::after{
  transform:scaleX(1); transform-origin:left;
}
/* core underlines the current page by default — we do it with the rule above */
.nav .wp-block-navigation .wp-block-navigation-item__content:focus,
.nav .wp-block-navigation .wp-block-navigation-item__content{ text-decoration:none; }

/* ---------- the mobile overlay core opens for us ----------
   Core hard-codes a white panel with black text whenever the navigation block
   carries no overlay colours of its own:

     .wp-block-navigation:not(.has-background)
       .wp-block-navigation__responsive-container.is-menu-open
       :not(.disable-default-overlay) { background-color: #fff }

   That is five class selectors. A three-class rule loses to it, which left a
   white panel with white links and a white close button — a blank screen with
   the page scroll locked behind it and nothing visible to tap. The selector
   below mirrors core's and adds .nav, so it outranks it in both schemes. */
.nav .wp-block-navigation:not(.has-background)
  .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay){
  background:var(--bg);
  color:var(--fg);
  padding:var(--gutter);
}
.nav .wp-block-navigation:not(.has-text-color)
  .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay){
  color:var(--fg);
}

.nav .wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation-item__content{
  font-size:clamp(1.75rem,7.5vw,3.5rem);
  font-weight:700; letter-spacing:-.04em;
  color:var(--fg);
  padding-block:.35rem;
}
.nav .wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation-item__content::after{ display:none; }

/* Belt and braces: the overlay lays out as a column, but if a long menu ever
   ends up in a row it wraps rather than running off the side. */
.nav .wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__container{
  flex-wrap:wrap;
  align-items:flex-start;
}

.nav .wp-block-navigation .wp-block-navigation__responsive-container-open,
.nav .wp-block-navigation .wp-block-navigation__responsive-container-close{
  color:var(--fg);
}

/* nav search — a pill that matches .btn's geometry without its fill-on-hover.
   Selectors are deliberately three-deep: core's block-library sheet styles
   .wp-block-search__inside-wrapper at two, and load order between it and the
   theme stylesheet isn't something to rely on. */
.nav__end{ min-width:0; }

/* The width must sit on the <form>, not on the inner wrapper: core renders
   .wp-block-search as a flex container whose __inside-wrapper is a flex item
   with flex-grow:1, so a width set on the wrapper is discarded by the flex
   algorithm and the field stretches to its intrinsic size. */
.nav .tz-search{
  margin:0;
  width:clamp(8rem, 17vw, 15rem);
  transition:width .4s var(--ease);
}
.nav .tz-search .wp-block-search__inside-wrapper{
  width:100%;
  border:0;
  border-bottom:1px solid var(--line);
  border-radius:0;
  background:transparent;
  padding:0 .2rem 0 0;
  transition:border-color .35s var(--ease);
}
.nav .tz-search .wp-block-search__inside-wrapper:focus-within{ border-bottom-color:var(--fg); }
.nav .tz-search .wp-block-search__input{
  min-width:0;
  border:0; background:none;
  color:var(--fg);
  font-size:var(--t-sm);
  padding:.55rem 0;
}
.nav .tz-search .wp-block-search__input::placeholder{ color:var(--faint); }
.nav .tz-search .wp-block-search__input:focus{ outline:none; }
.nav .tz-search .wp-block-search__button{
  background:none; border:0;
  color:var(--muted);
  padding:.3rem;
  transition:color .35s var(--ease);
}
.nav .tz-search .wp-block-search__button:hover{ color:var(--fg); }
.nav .tz-search .wp-block-search__button svg{ width:20px; height:20px; fill:currentColor; }

/* theme toggle — the mark's visual sibling, so it sits on the same optical row */
.tz-theme-toggle{
  display:inline-flex; align-items:center; justify-content:center;
  width:34px; height:34px;
  border:0;
  color:var(--muted);
  background:none; cursor:pointer;
  transition:color .35s var(--ease), transform .45s var(--ease);
}
.tz-theme-toggle:hover{ color:var(--fg); transform:rotate(-25deg); }
.tz-theme-toggle svg{ width:15px; height:15px; }
.tz-theme-toggle .tz-sun{ display:none; }
html.tz-light .tz-theme-toggle .tz-sun{ display:block; }
html.tz-light .tz-theme-toggle .tz-moon{ display:none; }

/* ==========================================================================
   SHARED BITS
   ========================================================================== */
.eyebrow{
  display:flex; align-items:center; gap:.6rem;
  font-size:var(--t-xs);
  font-weight:500;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--faint);
  font-variant-numeric:tabular-nums;
}
.eyebrow__dot{
  width:6px; height:6px; border-radius:50%;
  background:var(--fg);
  animation:pulse 2.6s var(--ease-io) infinite;
  flex:none;
}
@keyframes pulse{
  0%,100%{ opacity:1; transform:scale(1); }
  50%{ opacity:.35; transform:scale(.7); }
}

.h2{
  font-size:var(--t-h2);
  font-weight:700;
  line-height:.96;
  letter-spacing:-.045em;
  max-width:18ch;
}
.h2 em{ font-style:normal; color:var(--faint); }

strong,.hl{ color:var(--fg); font-weight:inherit; }

/* buttons */
.btn{
  position:relative;
  display:inline-flex; align-items:center; justify-content:center;
  padding:1.1rem 2rem;
  border-radius:100px;
  border:1px solid var(--fg);
  font-size:var(--t-sm); font-weight:500;
  letter-spacing:-.01em;
  overflow:hidden;
  isolation:isolate;
  transition:color .45s var(--ease), border-color .45s var(--ease);
}
.btn::before{
  content:""; position:absolute; inset:0; z-index:-1;
  background:var(--fg);
  transform:translateY(101%);
  transition:transform .55s var(--ease);
}
.btn:hover{ color:var(--bg); }
.btn:hover::before{ transform:translateY(0); }
.btn--sm{ padding:.7rem 1.35rem; }
.btn--lg{ padding:1.35rem 2.75rem; font-size:var(--t-lg); font-weight:600; }

.link-arrow{
  display:inline-flex; align-items:center; gap:.55rem;
  font-size:var(--t-sm); color:var(--muted);
  transition:color .35s var(--ease), gap .35s var(--ease);
}
.link-arrow::after{ content:"→"; transition:transform .45s var(--ease); }
.link-arrow:hover{ color:var(--fg); gap:.85rem; }
.link-arrow:hover::after{ transform:translateX(3px); }

/* ---------- reveal system ---------- */
[data-reveal]{
  opacity:0;
  transform:translateY(26px);
  transition:opacity .95s var(--ease), transform .95s var(--ease);
  transition-delay:calc(var(--i, 0) * 90ms);
}
[data-reveal].is-in{ opacity:1; transform:none; }

/* ==========================================================================
   BLOG — archive / index listing
   ========================================================================== */
.tz-page-head{
  padding-block:clamp(3rem,7vw,6rem) clamp(2.5rem,5vw,4rem);
}
.tz-page-head .eyebrow{ margin-bottom:1.75rem; }
.tz-page-head__title{
  font-size:var(--t-h2);
  font-weight:700; line-height:.96; letter-spacing:-.045em;
  max-width:18ch;
}
/* The search head carries only a title — the results are the point, so it
   gets out of the way rather than filling the first screen. */
.tz-page-head--compact{
  padding-block:clamp(2rem,4vw,3.25rem) clamp(1.25rem,2.5vw,2rem);
}
.tz-page-head--compact .tz-page-head__title{
  font-size:clamp(1.75rem, 1.15rem + 2.2vw, 3rem);
  max-width:none;
  letter-spacing:-.035em;
}

/* The site name, set the way the landing page sets its hero: as big as the
   column allows, tight tracking, leading pulled in under 1. Shown only on the
   first screen of the list — page two and every search result open straight
   on the posts. */
.tz-page-head--hero{ display:none; }
body.tz-home-first .tz-page-head--hero{
  display:block;
  padding-block:clamp(2.5rem,6vw,5rem) clamp(2rem,4vw,3.5rem);
}
.tz-page-head--hero .tz-page-head__title{
  font-size:clamp(2.75rem, 1.2rem + 6vw, 7rem);
  font-weight:800;
  line-height:.92;
  letter-spacing:-.05em;
  max-width:14ch;
}
/* The site tagline, set as the hero's subhead. Sized well below the name so
   it reads as a second voice rather than competing with it. */
.tz-page-head--hero .tz-page-head__tagline{
  margin-top:clamp(1.25rem, 2.5vw, 2rem);
  max-width:46ch;
  font-size:var(--t-lg);
  line-height:1.45;
  letter-spacing:-.015em;
  color:var(--muted);
}

.tz-page-head__sub{
  margin-top:clamp(1.5rem,3vw,2.25rem);
  max-width:52ch;
  color:var(--muted);
  font-size:var(--t-lg);
  line-height:1.45;
}

/* The list is a stack of hairline-separated rows rather than cards — the
   landing page never boxes anything, and boxes would read as a different
   product. Hover lifts the whole row from muted to full contrast. */
.tz-posts{ border-top:1px solid var(--line); }

.tz-post{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,320px);
  gap:clamp(1.5rem,4vw,4rem);
  align-items:start;
  padding-block:clamp(2rem,4vw,3.25rem);
  border-bottom:1px solid var(--line);
}
.tz-post__meta{
  display:flex; align-items:baseline; gap:.75rem; flex-wrap:wrap;
  font-size:var(--t-xs);
  letter-spacing:.14em; text-transform:uppercase;
  color:var(--faint);
  font-variant-numeric:tabular-nums;
  margin-bottom:1.1rem;
}
/* The category is a sibling block, so WP's flow layout hands it a
   margin-block-start; in a flex row that drops it below the date's baseline
   instead of sitting beside it. */
.tz-post__meta > *{ margin-block-start:0; }
.tz-post__meta a{ color:inherit; transition:color .35s var(--ease); }
.tz-post__meta a:hover{ color:var(--fg); }

.tz-post__title{
  font-size:var(--t-xl);
  font-weight:700; line-height:1.05; letter-spacing:-.035em;
  max-width:24ch;
}
.tz-post__title a{
  background-image:linear-gradient(var(--fg),var(--fg));
  background-size:0% 1px;
  background-position:0 100%;
  background-repeat:no-repeat;
  transition:background-size .5s var(--ease);
}
.tz-post__title a:hover{ background-size:100% 1px; }

.tz-post__excerpt{
  margin-top:1rem;
  color:var(--muted);
  max-width:56ch;
  line-height:1.55;
}
.tz-post__more{ margin-top:1.35rem; }

/* Not every post carries a featured image — Amphibious never required one, so
   plenty of the imported ones won't have it. Without this the copy sits in two
   thirds of the row and the last third is empty for no visible reason. */
.tz-post:not(:has(.tz-post__media img)){ grid-template-columns:1fr; }
.tz-post:not(:has(.tz-post__media img)) .tz-post__media{ display:none; }

.tz-post__media img{
  width:100%;
  aspect-ratio:16/10;
  object-fit:cover;
  filter:grayscale(1) contrast(1.05);
  opacity:.82;
  transition:opacity .6s var(--ease), filter .6s var(--ease),
             transform .8s var(--ease);
}
.tz-post:hover .tz-post__media img{
  opacity:1; filter:grayscale(0) contrast(1); transform:scale(1.02);
}

/* ---------- pagination ----------
   Newer on the left, older on the right, page numbers centred between them —
   the same eyebrow treatment used everywhere else, so it reads as a caption to
   the list rather than a widget bolted underneath it. */
/* Three fixed tracks rather than space-between: on the first and last page one
   end is missing, and with flex the numbers would centre themselves in
   whatever space was left over instead of on the page. Doubled class beats the
   block's own generated layout rule. */
.tz-pagination.wp-block-query-pagination{
  display:grid;
  grid-template-columns:1fr auto 1fr;
  align-items:baseline;
  gap:1.5rem;
  margin-top:clamp(2.5rem,5vw,4rem);
  padding-block:clamp(1.5rem,3vw,2.25rem);
  border-top:1px solid var(--line);
  font-size:var(--t-xs);
  font-weight:500;
  letter-spacing:.14em;
  text-transform:uppercase;
}
.tz-pagination > *{ margin-block-start:0; }

.tz-pagination .wp-block-query-pagination-previous,
.tz-pagination .wp-block-query-pagination-next{
  display:inline-flex;
  align-items:center;
  gap:.7rem;
  color:var(--faint);
  transition:color .35s var(--ease);
}
.tz-pagination .wp-block-query-pagination-previous{ grid-column:1; justify-self:start; }
.tz-pagination .wp-block-query-pagination-next{ grid-column:3; justify-self:end; }
.tz-pagination .wp-block-query-pagination-previous:hover,
.tz-pagination .wp-block-query-pagination-next:hover{ color:var(--fg); }

/* Arrows drawn here rather than baked into the labels, so they can travel
   without dragging the words along. */
.tz-pagination .wp-block-query-pagination-previous::before,
.tz-pagination .wp-block-query-pagination-next::after{
  font-size:1.15em;
  line-height:1;
  transition:transform .45s var(--ease);
}
.tz-pagination .wp-block-query-pagination-previous::before{ content:"<"; }
.tz-pagination .wp-block-query-pagination-next::after{ content:">"; }
.tz-pagination .wp-block-query-pagination-previous:hover::before{ transform:translateX(-.2em); }
.tz-pagination .wp-block-query-pagination-next:hover::after{ transform:translateX(.2em); }

.tz-pagination .wp-block-query-pagination-numbers{
  grid-column:2;
  justify-self:center;
  display:flex;
  align-items:baseline;
  gap:1.15rem;
  font-variant-numeric:tabular-nums;
  letter-spacing:.06em;
}
.tz-pagination .page-numbers{
  color:var(--faint);
  padding-bottom:.4rem;
  border-bottom:1px solid transparent;
  transition:color .35s var(--ease), border-color .35s var(--ease);
}
.tz-pagination a.page-numbers:hover{ color:var(--fg); border-bottom-color:var(--line); }
.tz-pagination .page-numbers.current{ color:var(--fg); border-bottom-color:var(--fg); }
.tz-pagination .page-numbers.dots{ border-bottom-color:transparent; }

/* ==========================================================================
   BLOG — single post
   ========================================================================== */
/* ---------- post hero ----------
   The featured image is the header. It runs full-bleed and cancels the fixed
   nav's clearance so the nav floats over the image rather than sitting on a
   band above it. */
.tz-hero{ position:relative; }

/* When the post has a hero the page opens on the image, so both offsets above
   it have to go: the fixed-nav clearance on .wp-site-blocks and the layout gap
   WordPress puts above <main>. Cancelled at their source rather than guessed
   at with a negative margin, which would have to track WP's block gap. */
.wp-site-blocks:has(.tz-hero img){ padding-top:0; }
main:has(> .tz-hero img){ margin-top:0; }

.tz-hero .tz-hero__media{ margin:0; }
.tz-hero img{
  width:100%;
  height:clamp(19rem, 54vh, 34rem);
  object-fit:cover;
  filter:grayscale(1) contrast(1.05);
}

/* The caption box reproduces the content wrap's geometry exactly — same
   max-width plus the same gutter — so the overlaid title lands on the very
   same left edge as the date below it, at every viewport width. */
.tz-hero__caption{
  position:absolute;
  left:0; right:0;
  bottom:clamp(1.25rem, 3vw, 2.5rem);
  max-width:calc(var(--wrap) + var(--gutter) * 2);
  margin-inline:auto;
  padding-inline:var(--gutter);
}

/* Set into the image like selected text: inline so the black box hugs each
   line, cloned so every wrapped line keeps its padding. Fixed black/white
   rather than --bg/--fg — this stays a black highlight in both schemes. */
/* Leading has to clear the highlight, not just the glyphs.
   Each wrapped line paints its own black box, sized to the font's full content
   area (~1.21em in Inter) plus the vertical padding. At line-height 1.18 those
   boxes overlapped, and since inline fragments paint in document order, line
   two's box covered line one's descenders — the tail of a "g" disappearing.

   Draw order can't be reordered per line: z-index doesn't apply to inline
   fragments, so there is no way to put line one on top without also putting
   its box over line two's ascenders — trading one clipped letter for another.
   The fix is to stop the boxes overlapping at all: line-height must exceed
   content area + 2 × padding-block (1.21 + 0.10 = 1.31em here). 1.36 leaves a
   hairline of image visible between the bars, which is also what makes them
   read as separate highlights rather than one ragged slab. */
.tz-hero__title{
  display:inline;
  font-size:clamp(1.75rem, 1rem + 3vw, 4rem);
  font-weight:700;
  line-height:1.36;
  letter-spacing:-.04em;
  color:var(--white);
  background:var(--black);
  padding:.05em .3em;
  box-decoration-break:clone;
  -webkit-box-decoration-break:clone;
}

/* No featured image: the title drops back into normal flow. The caption keeps
   its wrap geometry — .tz-hero is still full-bleed, so without the max-width
   and gutter the title would start at the viewport edge instead of the same
   left rule as the date. The highlight goes too: a black box only reads as
   set-into-the-image when there is an image. */
.tz-hero:not(:has(img)) .tz-hero__caption{
  position:static;
  padding-block:clamp(1.5rem,4vw,3rem) clamp(.5rem,1.5vw,1rem);
}
.tz-hero:not(:has(img)) .tz-hero__title{
  display:block;
  background:none;
  color:var(--fg);
  padding:0;
  font-size:clamp(2rem, 1.2rem + 3.4vw, 4.5rem);
  line-height:.98;
  letter-spacing:-.045em;
  max-width:20ch;
}

/* Date + category on the left, the post's tags pushed to the right rule. */
/* The lead image: the same featured image as the hero, but in colour and at
   the reading measure. The hero stays desaturated as the page's header; this
   is the first thing in the article itself. */
.tz-entry-lead{ padding-top:clamp(2rem,4vw,3rem); }
.tz-entry-lead:not(:has(img)){ display:none; }
.tz-entry-lead img{
  width:100%;
  filter:none;
}
.tz-entry-lead .wp-block-post-featured-image{ margin:0; }

.tz-entry-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:1rem 2rem;
  flex-wrap:wrap;
  padding-block:clamp(1.25rem,3vw,2rem) clamp(1rem,2.5vw,1.5rem);
  border-bottom:1px solid var(--line);
}
.tz-entry-head > *{ margin-block-start:0; }
/* still used by page.html, which has no hero */
.tz-entry-head__title{
  font-size:clamp(2rem, 1.2rem + 3.4vw, 4.5rem);
  font-weight:700; line-height:.98; letter-spacing:-.045em;
  max-width:20ch;
}
.tz-entry-head__meta{
  display:flex; gap:.75rem; align-items:baseline; flex-wrap:wrap;
  font-size:var(--t-xs);
  letter-spacing:.14em; text-transform:uppercase;
  color:var(--faint);
  font-variant-numeric:tabular-nums;
}
.tz-entry-head__meta > *{ margin-block-start:0; }

/* Long-form body copy. Everything here is scoped to .tz-entry so the
   editor's own block styles keep working elsewhere. */
.tz-entry{ padding-block:clamp(2rem,4vw,3rem) clamp(3rem,6vw,5rem); }

.tz-entry > *{
  max-width:var(--read);
  margin-inline:auto;
}
/* full-bleed escapes for figures the author widens */
.tz-entry > .alignwide{ max-width:min(1100px,100%); }
.tz-entry > .alignfull{ max-width:none; }

.tz-entry p,
.tz-entry li{
  font-size:var(--t-base);
  line-height:1.68;
  color:var(--read-fg);
}
.tz-entry p{ margin-block:1.35em; }

.tz-entry h2,
.tz-entry h3,
.tz-entry h4{
  color:var(--fg);
  font-weight:700;
  letter-spacing:-.035em;
  line-height:1.1;
  margin-block:2.4em .8em;
}
.tz-entry h2{ font-size:var(--t-xl); }
.tz-entry h3{ font-size:var(--t-lg); }
.tz-entry h4{ font-size:var(--t-base); letter-spacing:-.02em; }

/* Button blocks are anchors too, and this rule was pinning their colour to
   --fg. On hover the button fills with --fg, so the label became invisible
   against its own background — and it inherited a body-link underline it was
   never meant to have. Buttons are styled by theme.json; exclude them. */
.tz-entry a:not(.btn):not(.wp-element-button):not(.wp-block-button__link){
  color:var(--fg);
  background-image:linear-gradient(var(--line),var(--line));
  background-size:100% 1px;
  background-position:0 100%;
  background-repeat:no-repeat;
  transition:background-size .4s var(--ease), background-image .4s var(--ease);
}
.tz-entry a:not(.btn):not(.wp-element-button):not(.wp-block-button__link):hover{
  background-image:linear-gradient(var(--fg),var(--fg));
}

.tz-entry ul,.tz-entry ol{ padding-left:1.35em; margin-block:1.35em; }
.tz-entry ul{ list-style:disc; }
.tz-entry ol{ list-style:decimal; }
.tz-entry li{ margin-block:.5em; }
.tz-entry li::marker{ color:var(--faint); }

.tz-entry blockquote{
  border-left:1px solid var(--fg);
  padding-left:clamp(1.25rem,3vw,2rem);
  margin-block:2.5em;
}
.tz-entry blockquote p{
  color:var(--fg);
  font-size:var(--t-lg);
  line-height:1.4;
  letter-spacing:-.02em;
}

.tz-entry code{
  font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  font-size:.875em;
  background:var(--hair);
  padding:.15em .4em;
  border-radius:3px;
  color:var(--fg);
}
.tz-entry pre{
  background:var(--hair);
  border:1px solid var(--line);
  border-radius:6px;
  padding:clamp(1rem,2.5vw,1.5rem);
  overflow-x:auto;
  margin-block:2em;
  font-size:var(--t-sm);
  line-height:1.6;
}
.tz-entry pre code{ background:none; padding:0; border-radius:0; }

.tz-entry hr{
  border:0;
  border-top:1px solid var(--line);
  margin-block:3em;
}

.tz-entry figcaption,
.tz-entry .wp-element-caption{
  font-size:var(--t-xs);
  color:var(--faint);
  letter-spacing:.02em;
  margin-top:.85rem;
  text-align:left;
}

/* A table wider than the measure has to scroll inside its own figure —
   otherwise it pushes the whole document sideways on narrow screens. */
.tz-entry .wp-block-table{ overflow-x:auto; }

.tz-entry table{
  width:100%;
  border-collapse:collapse;
  font-size:var(--t-sm);
  margin-block:2em;
}
.tz-entry th,.tz-entry td{
  border-bottom:1px solid var(--line);
  padding:.9rem 1.5rem;
  text-align:left;
  vertical-align:top;
}
/* Every cell keeps its padding, including the first and last columns. An
   earlier version zeroed the outer padding so the table's type aligned with
   the body copy above it, but that left the first column looking cramped
   against the second — the table now reads as its own inset block. */

.tz-entry th{
  color:var(--fg);
  font-weight:600;
  font-size:var(--t-xs);
  letter-spacing:.1em;
  text-transform:uppercase;
  padding-bottom:.7rem;
  border-bottom-color:var(--muted);
}
.tz-entry td{ color:var(--muted); }
.tz-entry tbody tr:last-child td{ border-bottom:0; }

/* The post's tags, set to match the category exactly — same size, tracking and
   colour — so the header reads as one line of metadata split left and right
   rather than two competing treatments. Inline flow, so core's comma
   separators do the separating. */
.tz-terms{
  font-size:var(--t-xs);
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--faint);
  font-variant-numeric:tabular-nums;
  text-align:right;
}
.tz-terms a{
  color:inherit;
  transition:color .35s var(--ease);
}
.tz-terms a:hover{ color:var(--fg); }

/* ---------- prev / next ----------
   The arrows are the navigation: oversized, faint until approached, and they
   travel outward on hover. Core renders them inside the link when the block's
   `arrow` attribute is set, so the whole glyph is part of the hit target. */
.tz-postnav{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:0;
  border-top:1px solid var(--line);
}
/* WP's flow layout again: the second grid item picks up a block gap and the
   two columns stop starting level. */
.tz-postnav > *{ margin-block-start:0; }

.tz-postnav__prev,
.tz-postnav__next{
  padding-block:clamp(2.5rem,6vw,4.5rem);
  /* anchor for the stretched hit target below */
  position:relative;
}

/* The arrow is a sibling of the <a>, not a child of it, so only the title was
   clickable — the large glyph looked like the control and wasn't one.
   Restructuring the block isn't possible from a template, so the anchor
   projects an overlay across its whole column instead: label, arrow and title
   become one target, and :hover still resolves through the anchor so the
   existing arrow animation fires from anywhere in the panel. */
.tz-postnav .wp-block-post-navigation-link a::after{
  content:"";
  position:absolute;
  inset:0;
  z-index:1;
}

/* First and last post: one side has no adjacent post, and core renders an
   empty wrapper. Without this the label sits there labelling nothing. */
.tz-postnav__prev:not(:has(a)) .tz-postnav__label,
.tz-postnav__next:not(:has(a)) .tz-postnav__label{ display:none; }
.tz-postnav__next:not(:has(a)){ border-left:0; }
.tz-postnav__next{
  text-align:right;
  border-left:1px solid var(--line);
  padding-left:clamp(1.5rem,4vw,3rem);
}
.tz-postnav__prev{ padding-right:clamp(1.5rem,4vw,3rem); }

.tz-postnav__label{
  font-size:var(--t-xs);
  letter-spacing:.14em; text-transform:uppercase;
  color:var(--faint);
  margin-bottom:.35rem;
}
.tz-postnav__title{
  font-size:var(--t-lg);
  font-weight:600; letter-spacing:-.025em; line-height:1.15;
  color:var(--muted);
  transition:color .35s var(--ease);
}
.tz-postnav__title a{ display:block; }
.tz-postnav a:hover{ color:var(--fg); }

/* Core puts the arrow before the link for "previous" and after it for "next",
   so the next arrow would sit under its title. Both blocks become columns and
   the arrow is ordered first, giving the pair a matching silhouette. */
.tz-postnav .wp-block-post-navigation-link{
  display:flex;
  flex-direction:column;
}
.tz-postnav__next .wp-block-post-navigation-link{ align-items:flex-end; }
.tz-postnav [class*="post-navigation-link__arrow"]{ order:-1; }

/* Core's glyphs are ← and →. Blanking the span and drawing the mark in a
   pseudo-element swaps them for chevrons without touching the block's
   attributes — and keeps the aria-hidden wrapper doing its job. */
.tz-postnav [class*="post-navigation-link__arrow"]{
  display:block;
  font-size:0;
  line-height:0;
  color:var(--faint);
  margin-bottom:.65rem;
  transition:transform .55s var(--ease), color .4s var(--ease);
}
.tz-postnav [class*="post-navigation-link__arrow"]::before{
  display:block;
  font-size:clamp(3.5rem, 9.5vw, 7rem);
  line-height:.8;
  font-weight:200;
  letter-spacing:0;
}
.tz-postnav__prev [class*="post-navigation-link__arrow"]::before{ content:"<"; }
.tz-postnav__next [class*="post-navigation-link__arrow"]::before{ content:">"; }
/* Core renders the arrow as a SIBLING of the <a>, not inside it, so the hover
   has to be taken on the wrapping block — and :focus-within so keyboard
   traversal animates identically. */
.tz-postnav__prev .wp-block-post-navigation-link:hover [class*="post-navigation-link__arrow"],
.tz-postnav__prev .wp-block-post-navigation-link:focus-within [class*="post-navigation-link__arrow"]{
  transform:translateX(-.09em);
  color:var(--fg);
}
.tz-postnav__next .wp-block-post-navigation-link:hover [class*="post-navigation-link__arrow"],
.tz-postnav__next .wp-block-post-navigation-link:focus-within [class*="post-navigation-link__arrow"]{
  transform:translateX(.09em);
  color:var(--fg);
}
.tz-postnav .wp-block-post-navigation-link:hover a{ color:var(--fg); }

/* ==========================================================================
   COMMENTS
   ========================================================================== */
.tz-comments{
  padding-block:clamp(3rem,6vw,5rem);
  border-top:1px solid var(--line);
}

.tz-comments__title{
  font-size:var(--t-xs);
  font-weight:500;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--faint);
  margin-bottom:clamp(2rem,4vw,3rem);
}

/* ---------- the thread ---------- */
.tz-comments .wp-block-comment-template{ list-style:none; padding:0; margin:0; }
.tz-comments .wp-block-comment-template li{ list-style:none; }

.tz-comment{
  padding-block:clamp(1.5rem,3vw,2.25rem);
  border-top:1px solid var(--hair);
}
.tz-comments .wp-block-comment-template > li:first-child > .tz-comment{
  border-top:0;
  padding-top:0;
}

/* Replies step in and carry a rule, so depth is legible at a glance rather
   than inferred from indentation alone. */
.tz-comments .wp-block-comment-template ol{
  list-style:none;
  margin:0;
  padding-left:clamp(1.25rem,3vw,2.75rem);
  border-left:1px solid var(--line);
}

.tz-comment__head{
  display:flex; align-items:center; gap:.9rem;
  margin-bottom:.9rem;
}
.tz-comment__head > *{ margin-block-start:0; }

.tz-comment__avatar img,
.tz-comment .wp-block-avatar img{
  width:40px; height:40px;
  border-radius:50%;
  filter:grayscale(1) contrast(1.05);
  flex:none;
}

.tz-comment__byline > *{ margin-block-start:0; }
.tz-comment__author{
  font-size:var(--t-sm);
  font-weight:600;
  letter-spacing:-.015em;
  color:var(--fg);
  line-height:1.2;
}
.tz-comment__author a{ color:inherit; }
.tz-comment__date{
  margin-top:.2rem;
  font-size:var(--t-xs);
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--faint);
  font-variant-numeric:tabular-nums;
}
.tz-comment__date a{ color:inherit; }

/* Body indented to the byline's left edge — avatar width plus its gap — so the
   author line and the text it belongs to share a spine. */
.tz-comment__body{
  padding-left:calc(40px + .9rem);
  color:var(--muted);
  font-size:var(--t-sm);
  line-height:1.65;
}
.tz-comment__body p{ margin-block:.65em; }
.tz-comment__body > *:first-child{ margin-top:0; }

.tz-comment__reply{
  padding-left:calc(40px + .9rem);
  margin-top:.85rem;
  font-size:var(--t-xs);
  letter-spacing:.14em;
  text-transform:uppercase;
}
.tz-comment__reply a{
  color:var(--faint);
  transition:color .35s var(--ease);
}
.tz-comment__reply a:hover{ color:var(--fg); }

.tz-comments__pagination{
  display:flex; gap:1.25rem; flex-wrap:wrap;
  margin-top:clamp(2rem,4vw,3rem);
  font-size:var(--t-sm);
  color:var(--muted);
}

/* ---------- the form ----------
   Fields borrow the nav search's treatment: no box, no fill, just a rule that
   lights up on focus. */
.tz-comment-form{ margin-top:clamp(3rem,6vw,4.5rem); }

.tz-comment-form .comment-reply-title,
.tz-comment-form h3{
  font-size:var(--t-xs);
  font-weight:500;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--faint);
  margin-bottom:1.75rem;
}

.tz-comment-form .comment-form{
  display:flex;
  flex-direction:column;
  gap:1.75rem;
}

.tz-comment-form label{
  display:block;
  font-size:var(--t-xs);
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--faint);
  margin-bottom:.5rem;
}

.tz-comment-form input:not([type="submit"]):not([type="checkbox"]),
.tz-comment-form textarea{
  width:100%;
  background:transparent;
  border:0;
  border-bottom:1px solid var(--line);
  border-radius:0;
  color:var(--fg);
  font-family:inherit;
  font-size:var(--t-sm);
  padding:.65rem 0;
  transition:border-color .35s var(--ease);
}
.tz-comment-form input:not([type="submit"]):not([type="checkbox"]):focus,
.tz-comment-form textarea:focus{
  outline:none;
  border-bottom-color:var(--fg);
}
/* The comment body is the one multi-line field, and a single bottom rule under
   a tall box leaves the text floating. Same colour and weight as the other
   fields, just carried the whole way round. */
.tz-comment-form textarea{
  border:1px solid var(--line);
  padding:.9rem 1.1rem;
  resize:vertical;
  min-height:8rem;
  line-height:1.6;
}
.tz-comment-form textarea:focus{ border-color:var(--fg); }
.tz-comment-form input::placeholder,
.tz-comment-form textarea::placeholder{ color:var(--faint); }

/* The preamble — "Logged in as …" when signed in, the email/required notice
   when not. WordPress emits these as sibling <span>s inside one <p>, so they
   run together as a single line of undifferentiated grey with no sign that
   half of it is clickable. Each notice becomes its own block, and the links
   get the same underline treatment as body copy. */
.tz-comment-form .comment-notes,
.tz-comment-form .logged-in-as,
.tz-comment-form .comment-form-cookies-consent label{
  display:block;
  margin:0;
  font-size:var(--t-xs);
  letter-spacing:.02em;
  text-transform:none;
  color:var(--faint);
  line-height:1.7;
}
/* WordPress appends the required-fields note inside .logged-in-as for signed-in
   users and inside .comment-notes for everyone else, so it is matched wherever
   it lands rather than under one parent. */
.tz-comment-form #email-notes,
.tz-comment-form .required-field-message{
  display:block;
}

.tz-comment-form .comment-notes a,
.tz-comment-form .logged-in-as a,
.tz-comment-form .comment-reply-title small a{
  color:var(--muted);
  background-image:linear-gradient(var(--line),var(--line));
  background-size:100% 1px;
  background-position:0 100%;
  background-repeat:no-repeat;
  transition:color .35s var(--ease), background-image .35s var(--ease);
}
.tz-comment-form .comment-notes a:hover,
.tz-comment-form .logged-in-as a:hover,
.tz-comment-form .comment-reply-title small a:hover{
  color:var(--fg);
  background-image:linear-gradient(var(--fg),var(--fg));
}

/* "Cancel reply", which WP tucks into the heading */
.tz-comment-form .comment-reply-title small{
  display:block;
  margin-top:.6rem;
  font-size:var(--t-xs);
  letter-spacing:.02em;
  text-transform:none;
}
.tz-comment-form .comment-form-cookies-consent{
  display:flex; align-items:flex-start; gap:.65rem;
}
.tz-comment-form .comment-form-cookies-consent label{ margin:0; }
.tz-comment-form input[type="checkbox"]{ accent-color:var(--fg); margin-top:.15rem; }

.tz-comment-form .required{ color:var(--muted); }

/* ==========================================================================
   FOOTER
   ========================================================================== */
.footer{
  border-top:1px solid var(--line);
  padding-block:0 clamp(2.5rem,5vw,4rem);
}

/* ---------- footer widget columns ---------- */
.tz-footer-cols{
  display:grid;
  /* Tags, Categories, Recent posts — the widest column trails, because post
     titles need the room and the two term lists do not. */
  grid-template-columns:1fr 1fr 1.5fr;
  /* start, not the default stretch: the columns hold lists of different
     lengths, and the section headings have to sit on one line */
  align-items:start;
  gap:clamp(2rem,5vw,5rem);
  padding-block:clamp(3rem,6vw,5rem);
  margin-bottom:clamp(2rem,4vw,3rem);
  border-bottom:1px solid var(--line);
}
/* .tz-footer-cols is still a wp-block-group, so WP's flow layout puts
   margin-block-start on every sibling after the first. Inside a grid that
   pushes columns two and three down by one block gap and the three headings
   no longer sit on a line. */
.tz-footer-cols > *{ margin-block-start:0; }
.tz-fcol > *:first-child{ margin-top:0; }

.tz-fcol__title{
  font-size:var(--t-xs);
  font-weight:500;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--faint);
  margin-bottom:1.5rem;
}

/* Recent posts */
.tz-recent{ display:flex; flex-direction:column; gap:1.1rem; }
.tz-recent li{ line-height:1.3; }
.tz-recent a{
  display:block;
  font-size:var(--t-sm);
  font-weight:500;
  letter-spacing:-.015em;
  color:var(--muted);
  transition:color .35s var(--ease);
}
.tz-recent a:hover{ color:var(--fg); }
.tz-recent .wp-block-latest-posts__post-date{
  display:block;
  margin-top:.4rem;
  font-size:var(--t-xs);
  color:var(--faint);
  font-variant-numeric:tabular-nums;
}

/* Tags — same chip as .tz-terms on the single post.
   The per-tag font-size is inlined by core; both ends of the block's range are
   set to .75rem so every chip lands on the same size instead of the default
   8pt–22pt spread, which reads as noise in a monochrome palette. */
.tz-tagcloud{ display:flex; flex-wrap:wrap; gap:.45rem 1.1rem; }
.tz-tagcloud a{
  letter-spacing:.1em;
  text-transform:uppercase;
  color:var(--faint);
  transition:color .35s var(--ease);
}
.tz-tagcloud a:hover{ color:var(--fg); }
.tz-tagcloud .tag-link-count{ color:var(--faint); }

/* Categories */
.tz-cats{ display:flex; flex-direction:column; gap:.75rem; }
.tz-cats li{
  font-size:var(--t-xs);
  color:var(--faint);
  font-variant-numeric:tabular-nums;
}
.tz-cats a{
  font-size:var(--t-sm);
  color:var(--muted);
  transition:color .35s var(--ease);
}
.tz-cats a:hover{ color:var(--fg); }
.footer__grid{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:2rem; flex-wrap:wrap;
}
/* The colour-scheme toggle lives here now, stacked above the tagline. */
.footer__brand{
  display:flex; flex-direction:column;
  align-items:flex-start;
  gap:1.1rem;
}
/* Mark and tagline are one link out to the main site. */
.footer__brand-line{ display:flex; align-items:center; gap:.85rem; }
.footer__brand p{
  font-size:var(--t-sm); color:var(--muted);
  white-space:nowrap;
  transition:color .35s var(--ease);
}
.footer__brand-line:hover p{ color:var(--fg); }
.footer .tz-theme-toggle{ margin-left:-7px; }
.footer__meta{
  display:flex; flex-direction:column; gap:.35rem;
  text-align:right;
  font-size:var(--t-xs);
  color:var(--faint);
  letter-spacing:.02em;
}
.footer__meta a{ transition:color .35s var(--ease); }
.footer__meta a:hover{ color:var(--fg); }

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */
@media (max-width:900px){
  .tz-footer-cols{ grid-template-columns:1fr 1fr; row-gap:clamp(2rem,5vw,3rem); }
}

@media (max-width:860px){
  /* Core drops the burger and shows the inline row from 600px up, which a real
     menu overflows long before there is room for it — at 760px the last item
     ran past the viewport and the search field sat entirely off-screen at
     836px, clipped by overflow-x:hidden with no scrollbar to reach it. The
     overlay is extended to the breakpoint the rest of the nav collapses at. */
  .nav .wp-block-navigation .wp-block-navigation__responsive-container:not(.is-menu-open){
    display:none;
  }
  .nav .wp-block-navigation .wp-block-navigation__responsive-container-open{
    display:flex;
  }

  .tz-post{ grid-template-columns:1fr; }
  .tz-post__media{ order:-1; margin-bottom:.5rem; }
  /* Stacked, the divider belongs between the two rows, not down one side. */
  .tz-postnav{ grid-template-columns:1fr; }
  .tz-postnav__prev{ padding-right:0; }
  .tz-postnav__next{
    text-align:left;
    border-left:0;
    border-top:1px solid var(--line);
    padding-left:0;
  }
}

@media (max-width:620px){
  /* Once the post header wraps, the tags get their own line and there is no
     right-hand rule left to sit against. */
  .tz-terms{ text-align:left; }

  /* The site name is a fixed string, so it can be sized to fit rather than
     allowed to break — "Triple Zero (B)Labs" split across two lines at the
     desktop minimum of 2.75rem. The tagline is short enough to hold on one
     line at any width this theme supports. */
  .tz-page-head--hero .tz-page-head__title{
    font-size:clamp(1.6rem, 8.4vw, 2.4rem);
    white-space:nowrap;
    max-width:none;
  }
  .tz-page-head--hero .tz-page-head__tagline{
    white-space:nowrap;
    font-size:var(--t-base);
  }

  /* Numbers take their own row above the two directions. */
  .tz-pagination.wp-block-query-pagination{
    grid-template-columns:1fr 1fr;
    row-gap:1.5rem;
  }
  .tz-pagination .wp-block-query-pagination-numbers{
    grid-column:1 / -1; grid-row:1;
  }
  .tz-pagination .wp-block-query-pagination-previous{ grid-row:2; }
  .tz-pagination .wp-block-query-pagination-next{ grid-column:2; grid-row:2; }

  .footer__grid{ flex-direction:column; align-items:flex-start; }
  .footer__meta{ text-align:left; }
  .tz-footer-cols{ grid-template-columns:1fr; }
  .nav__name{ font-size:var(--t-xs); }
}

/* Below this the nav carries brand, search, menu trigger and theme toggle in
   one row. The field shrinks to an icon-width pill that still expands on
   focus, rather than disappearing — search is the only way back to a post
   once the list is long. */
@media (max-width:560px){
  .nav .tz-search{ width:2.75rem; }

  /* Focused, the field spans the nav instead of growing in place — widening a
     flex item in a row this tight just pushes its own right edge past the
     viewport. .nav is fixed, so absolute positioning resolves against it. */
  .nav .tz-search:focus-within{
    position:absolute;
    left:var(--gutter);
    right:var(--gutter);
    width:auto;
    z-index:3;
  }

  .nav .tz-search .wp-block-search__inside-wrapper{
    padding:0;
    justify-content:center;
  }
  .nav .tz-search:focus-within .wp-block-search__inside-wrapper{
    padding-left:1rem;
    justify-content:flex-start;
    /* opaque, or the brand and toggle read through the overlay */
    background:var(--bg);
  }
  /* min-width:0 as well as width:0 — a flex item's automatic minimum size
     would otherwise hold the input open at its intrinsic width. */
  .nav .tz-search .wp-block-search__input{
    width:0; min-width:0; padding:.5rem 0;
  }
  .nav .tz-search:focus-within .wp-block-search__input{ width:auto; }
}

/* ==========================================================================
   REDUCED MOTION
   ========================================================================== */
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  [data-reveal]{ opacity:1; transform:none; }
  .grain{ display:none; }
}
