/*
Theme Name: TMQ Platform
Theme URI: https://coffeewoodmarble.com
Description: Knowledge-first B2B platform for Terrazzo — material definition, specification and process explained before supply. Zero-plugin core: custom post types, taxonomies, aggregation homepage, lead capture.
Version: 1.0.0
Author: Platform Engineering
License: MIT
Text Domain: tmq-platform
*/

:root{
  --ink:#0b0b0d;          /* deep black */
  --ink-2:#14130f;        /* warm black */
  --panel:#1a1813;
  --panel-2:#252219;
  --line:#322d22;
  --muted:#9b9488;
  --text:#F2ECE1;         /* rice */
  --text-soft:#d8cfc0;
  --gold:#C9A86A;         /* luxury gold accent */
  --gold-soft:#e3d3a8;
  --gold-deep:#a8842f;
  --ok:#5db37a;
  --danger:#e06c5a;
  --radius:14px;
  --shadow:0 10px 30px rgba(0,0,0,.45);
  --maxw:1200px;
}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;background:var(--ink);color:var(--text);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,"PingFang SC","Microsoft YaHei",sans-serif;
  line-height:1.6;font-size:16px;-webkit-font-smoothing:antialiased;
}
a{color:var(--gold-soft);text-decoration:none;transition:color .15s}
a:hover{color:var(--gold)}
img{max-width:100%;display:block}
.container{max-width:var(--maxw);margin:0 auto;padding:0 20px}
.muted{color:var(--muted)}

/* ---------- top bar ---------- */
/* ---------- top bar (simple single row) ---------- */
.topbar{
  position:sticky;top:0;z-index:80;
  background:rgba(18,17,14,.94);
  backdrop-filter:saturate(140%) blur(10px);
  border-bottom:1px solid var(--line);
}
.topbar-in{display:flex;align-items:center;gap:24px;min-height:66px}

.brand{display:flex;align-items:center;gap:11px;font-weight:700;font-size:18.5px;color:var(--text);letter-spacing:.2px;flex:0 0 auto}
.brand .mark{
  width:34px;height:34px;border-radius:9px;flex:0 0 auto;
  display:inline-flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,var(--gold),var(--gold-deep));
  color:#1a1405;font-weight:800;font-size:17px;
}
.brand b{color:var(--gold-soft);font-weight:700}
.brand:hover .brand-txt{color:var(--gold-soft)}
.brand-txt{white-space:nowrap;transition:color .18s}

.nav-wrap{display:flex;align-items:center;gap:18px;margin-left:auto;min-width:0}
.nav{display:flex;align-items:center;gap:2px}
.nav a{
  color:var(--text-soft);text-decoration:none;font-size:14.5px;
  padding:9px 13px;border-radius:9px;white-space:nowrap;transition:color .16s,background .16s;
}
.nav a:hover{color:var(--text);background:var(--panel)}
.nav a.is-current{color:var(--gold-soft);background:rgba(201,168,106,.1)}
/* "Post Your Needs" occupies a nav slot but is the buyer's primary action —
   outlined gold, never a filled block, so the nav row keeps one weight. */
.nav a.nav-pyn{
  color:var(--gold-soft);
  border:1px solid rgba(201,168,106,.55);
  background:rgba(201,168,106,.10);
  font-weight:700;
}
.nav a.nav-pyn:hover{
  color:#1a1405;background:linear-gradient(135deg,var(--gold),var(--gold-deep));
  border-color:var(--gold);box-shadow:0 3px 12px rgba(201,168,106,.3);
}
.nav a.nav-pyn.is-current{color:var(--gold-soft);background:rgba(201,168,106,.18)}

.nav-cta{display:flex;align-items:center;gap:16px;flex:0 0 auto;margin-left:4px}

/* Secondary account actions: quiet text links. B2B buyers scanning the bar
   should see exactly one loud action, not three competing buttons. */
.nav-cta-minor{display:flex;align-items:center;gap:9px;flex:0 0 auto}
.nav-link-plain{
  color:var(--muted);text-decoration:none;font-size:13.5px;font-weight:500;
  padding:4px 2px;white-space:nowrap;transition:color .16s;
}
.nav-link-plain:hover{color:var(--gold-soft)}
.nav-dot{color:var(--line);font-size:13px;user-select:none}
.btn{
  display:inline-flex;align-items:center;justify-content:center;
  border-radius:10px;padding:10px 17px;font-size:14.5px;font-weight:600;
  text-decoration:none;white-space:nowrap;cursor:pointer;border:1px solid transparent;
  transition:filter .16s,background .16s,color .16s;
}
.btn-ghost{background:transparent;border-color:var(--line);color:var(--text-soft)}
.btn-ghost:hover{border-color:var(--gold);color:var(--gold-soft)}
.btn-gold{background:linear-gradient(135deg,var(--gold),var(--gold-deep));color:#1a1405;font-weight:700}
.btn-gold:hover{filter:brightness(1.07)}
/* "Post Your Needs" — the buyer's primary action, given the highest visual
   weight in the bar (solid gold, slightly larger) so it reads as the fastest
   conversion path, mirroring StoneContact's top-bar quick entry. */
.btn-need{
  background:linear-gradient(135deg,#D9BC7E,var(--gold),var(--gold-deep));
  color:#161005;font-weight:800;font-size:15.5px;letter-spacing:.2px;
  padding:12px 22px;border-radius:11px;
  box-shadow:0 4px 18px rgba(201,168,106,.30);
  transition:transform .16s,box-shadow .16s,filter .16s;
}
.btn-need:hover{
  transform:translateY(-1px);filter:brightness(1.06);
  box-shadow:0 8px 26px rgba(201,168,106,.44);
}
.btn-need:active{transform:translateY(0)}

/* Mobile toggle.
   ROOT CAUSE of the "white dot" in the header: the burger <button> was only
   given `display:none` on desktop but never had its UA default background
   neutralised. A <button> paints with the platform default
   `background-color: ButtonFace` (≈ rgb(239,239,239) — near-white). Inside the
   sticky bar's backdrop-filter stacking context some engines still composite
   that hidden button's face, showing up as a small white speck. So we hide it
   properly AND reset its paint, in every state. */
.nav-burger{
  /* ROOT CAUSE of the persistent "white dot" in the header: this <button>'s
     UA default `background-color: ButtonFace` (≈ #EFEFEF, near-white). Inside
     the sticky bar's backdrop-filter stacking context some engines still
     composite that face even while the button is `display:none`, painting a
     small white speck. Fix: reset EVERY paint property in all states and make
     the desktop box zero-sized + off-canvas so there is nothing to composite.
     A bare `display:none` alone is NOT enough. */
  display:none;
  width:0;height:0;min-width:0;min-height:0;
  margin:0;padding:0;border:0;outline:0;
  overflow:hidden;visibility:hidden;
  background:transparent;background-color:transparent;background-image:none;
  box-shadow:none;
  -webkit-appearance:none;appearance:none;
  color:inherit;font:inherit;
  position:absolute;left:-9999px;top:-9999px;
}
.nav-burger > span{background:transparent;border:0;box-shadow:none}
@media(max-width:900px){
  .topbar-in{flex-wrap:wrap;min-height:58px;gap:12px}
  .nav-burger{
    display:inline-flex;flex-direction:column;justify-content:center;gap:5px;
    position:static;visibility:visible;overflow:visible;
    width:42px;height:42px;min-width:42px;min-height:42px;margin-left:auto;cursor:pointer;
    border:1px solid var(--line);border-radius:10px;
    background:var(--panel);background-image:none;box-shadow:none;
    padding:0 10px;-webkit-appearance:none;appearance:none;
  }
  .nav-burger span{display:block;height:2px;width:100%;background:var(--text);border-radius:2px;transition:transform .2s,opacity .2s}
  .nav-wrap{
    order:3;width:100%;margin-left:0;flex-direction:column;align-items:stretch;gap:12px;
    padding:0 0 16px;display:none;
  }
  .nav-wrap.is-open{display:flex}
  .nav{flex-direction:column;align-items:stretch;gap:0}
  .nav a{padding:12px 14px;font-size:15.5px}
  .nav a.nav-pyn{margin-top:4px;text-align:center}
  .nav-cta{flex-direction:column-reverse;align-items:stretch;gap:14px;padding-top:4px}
  .nav-cta .btn{width:100%;padding:15px 18px}
  .nav-cta-minor{justify-content:center;gap:10px;padding-top:2px}
  .nav-link-plain{font-size:14.5px;padding:6px 4px}
  .nav-burger.is-open span:nth-child(1){transform:translateY(7px) rotate(45deg)}
  .nav-burger.is-open span:nth-child(2){opacity:0}
  .nav-burger.is-open span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
}
@media(max-width:560px){
  .brand-txt{font-size:16.5px}
  .brand .mark{width:30px;height:30px;font-size:15px}
}

/* ---------- hero ---------- */
.hero{
  position:relative;padding:64px 0 54px;
  background:
    radial-gradient(900px 380px at 78% -10%,rgba(201,168,106,.18),transparent 60%),
    radial-gradient(700px 320px at 10% 110%,rgba(201,168,106,.08),transparent 55%),
    linear-gradient(180deg,#0b0b0d,#14130f);
  border-bottom:1px solid var(--line);
}
.hero .eyebrow{color:var(--gold);font-weight:600;letter-spacing:2px;text-transform:uppercase;font-size:12.5px}
.hero h1{
  font-size:clamp(34px,5.4vw,60px);line-height:1.05;margin:12px 0 14px;font-weight:800;letter-spacing:-.5px;
}
.hero h1 .accent{background:linear-gradient(135deg,var(--gold-soft),var(--gold-deep));-webkit-background-clip:text;background-clip:text;color:transparent}
/* ⛔ 680px was 76 characters a line at 18px. The measure is 31em. */
.hero p.lead{font-size:18px;color:var(--text-soft);max-width:30em;margin:0 0 26px}
.searchbar{display:flex;gap:10px;max-width:680px;flex-wrap:wrap}
.searchbar input[type=text]{
  flex:1;min-width:240px;background:var(--panel);border:1px solid var(--line);color:var(--text);
  padding:14px 16px;border-radius:11px;font-size:15px;outline:none;
}
.searchbar input[type=text]:focus{border-color:var(--gold)}
.searchbar button{
  background:linear-gradient(135deg,var(--gold),var(--gold-deep));color:#1a1405;border:0;
  padding:14px 22px;border-radius:11px;font-weight:700;cursor:pointer;font-size:15px;
}
.hero-stats{display:flex;gap:30px;margin-top:34px;flex-wrap:wrap}
.hero-stats .stat .n{font-size:26px;font-weight:800;color:var(--gold-soft)}
.hero-stats .stat .l{font-size:13px;color:var(--muted);text-transform:uppercase;letter-spacing:1px}

/* ---------- sections ---------- */
.section{padding:52px 0}
.section-head{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;margin-bottom:26px;flex-wrap:wrap}
.section-head h2{font-size:28px;margin:0;font-weight:800;letter-spacing:-.3px}
.section-head .sub{color:var(--muted);font-size:14.5px;margin-top:4px}
.section-head a.more{color:var(--gold-soft);font-weight:600;font-size:14px}

/* filters */
.filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:24px}
.filters a{
  border:1px solid var(--line);background:var(--panel);color:var(--text-soft);
  padding:7px 14px;border-radius:999px;font-size:13.5px;
}
.filters a:hover,.filters a.active{border-color:var(--gold);color:var(--gold-soft);background:var(--panel-2)}

/* grids */
.grid{display:grid;gap:20px}
.grid-3{grid-template-columns:repeat(3,1fr)}
.grid-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:980px){.grid-4{grid-template-columns:repeat(2,1fr)}.grid-3{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.grid-4,.grid-3{grid-template-columns:1fr}}

.card{
  background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;display:flex;flex-direction:column;transition:transform .18s,border-color .18s,box-shadow .18s;
}
.card:hover{transform:translateY(-4px);border-color:var(--gold);box-shadow:var(--shadow)}
.card .thumb{aspect-ratio:4/3;background:var(--panel-2);position:relative;overflow:hidden}
.card .thumb img{width:100%;height:100%;object-fit:cover}
.card .thumb .ph{
  position:absolute;inset:0;display:grid;place-items:center;
  background:linear-gradient(135deg,#20262f,#2c3543);color:var(--muted);font-size:13px;
}
.card .body{padding:15px 16px;display:flex;flex-direction:column;gap:8px;flex:1;min-width:0}
.card .kicker{font-size:11.5px;text-transform:uppercase;letter-spacing:1px;color:var(--gold)}
/* Titles wrap to two lines and stop. A longer one pushed the price row out of
   the card entirely, which is what made the archive look broken once real
   photographs started filling the frames. */
.card h3{margin:0;font-size:16.5px;line-height:1.3;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.card .meta{font-size:13px;color:var(--muted);display:flex;gap:10px;flex-wrap:wrap}
.card .meta .tag{background:var(--panel-2);border:1px solid var(--line);padding:2px 9px;border-radius:999px}
/* The excerpt is a summary, not the specification. Clamping it keeps every card
   the same height and keeps the price row visible without a scrollbar. */
.card .excerpt{
  font-size:13px;line-height:1.55;color:var(--text-soft);margin:0;
  display:-webkit-box;-webkit-line-clamp:3;line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
}
.card .foot{
  margin-top:auto;padding-top:10px;border-top:1px solid var(--line);
  display:flex;align-items:center;justify-content:space-between;gap:8px;
}
.card .foot .price{font-size:13px;line-height:1.4;min-width:0}
.card .price{color:var(--gold-soft);font-weight:700}
.chip{font-size:12px;color:var(--muted)}

/* supplier card variant */
.supplier .thumb{aspect-ratio:16/7}
.supplier .logo{
  position:absolute;left:14px;bottom:-22px;width:54px;height:54px;border-radius:12px;
  background:linear-gradient(135deg,var(--gold),var(--gold-deep));display:grid;place-items:center;
  color:#1a1405;font-weight:800;font-size:20px;box-shadow:var(--shadow);border:2px solid var(--panel);
}
.supplier .body{padding-top:30px}

/* CTA band */
.cta-band{
  background:linear-gradient(135deg,#1a2230,#11161d);border:1px solid var(--line);
  border-radius:18px;padding:38px;display:flex;align-items:center;justify-content:space-between;gap:24px;flex-wrap:wrap;margin:10px 0;
}
.cta-band h2{margin:0 0 6px;font-size:26px}
.cta-band p{margin:0;color:var(--text-soft)}
.cta-band a.btn{
  background:linear-gradient(135deg,var(--gold),var(--gold-deep));color:#1a1405;font-weight:700;
  padding:14px 26px;border-radius:11px;white-space:nowrap;
}

/* ---------- single ---------- */
.single-wrap{padding:44px 0}
.back-link{color:var(--muted);font-size:14px;margin-bottom:18px;display:inline-block}
/* The picture column is deliberately the wider one. A rail needs room to show
   more than one photograph at a time - that is the entire point of it - and at
   an even split a 1400px screen gave the track 641px, enough for one picture
   and a sliver of the next, which is the single-frame layout with extra
   scrolling. */
.single-grid{display:grid;grid-template-columns:1.35fr .85fr;gap:34px;align-items:start}
@media(max-width:880px){.single-grid{grid-template-columns:1fr}}
.gallery{display:grid;gap:12px}
.gallery .main{border-radius:14px;overflow:hidden;border:1px solid var(--line);aspect-ratio:4/3;background:var(--panel-2)}
.gallery .main img{width:100%;height:100%;object-fit:cover}
.single h1{font-size:32px;margin:0 0 8px;letter-spacing:-.4px}
.single .sub{color:var(--muted);margin-bottom:18px}
.spec-table{width:100%;border-collapse:collapse;margin:18px 0}
.spec-table td{padding:11px 12px;border-bottom:1px solid var(--line);font-size:14.5px}
.spec-table td:first-child{color:var(--muted);width:40%}
.tagrow{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}
.tagrow a,.tagrow span{background:var(--panel-2);border:1px solid var(--line);padding:5px 12px;border-radius:999px;font-size:13px;color:var(--text-soft)}

/* ---------- inquiry form ---------- */
.form-card{max-width:640px;background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:30px}
.field{margin-bottom:16px}
.field label{display:block;font-size:13.5px;color:var(--text-soft);margin-bottom:6px;font-weight:600}
.field input,.field textarea,.field select{
  width:100%;background:var(--ink-2);border:1px solid var(--line);color:var(--text);
  padding:12px 14px;border-radius:10px;font-size:15px;outline:none;font-family:inherit;
}
.field input:focus,.field textarea:focus,.field select:focus{border-color:var(--gold)}
.field textarea{min-height:110px;resize:vertical}
.btn-submit{
  background:linear-gradient(135deg,var(--gold),var(--gold-deep));color:#1a1405;border:0;
  padding:14px 24px;border-radius:11px;font-weight:700;cursor:pointer;font-size:15px;width:100%;
}
.notice{padding:12px 16px;border-radius:10px;margin-bottom:18px;font-size:14.5px}
.notice.ok{background:rgba(93,179,122,.14);border:1px solid var(--ok);color:#bff0cd}
.notice.err{background:rgba(224,108,90,.14);border:1px solid var(--danger);color:#f3c4bc}

/* ---------- footer ---------- */
footer.site{border-top:1px solid var(--line);background:var(--ink-2);margin-top:40px;padding:38px 0 26px}
footer.site .cols{display:flex;gap:40px;flex-wrap:wrap;justify-content:space-between}
footer.site h4{font-size:14px;color:var(--text);margin:0 0 12px;letter-spacing:.5px}
footer.site a{display:block;color:var(--muted);font-size:13.5px;padding:3px 0}
footer.site a:hover{color:var(--gold-soft)}
footer.site .copy{margin-top:26px;color:var(--muted);font-size:12.5px;border-top:1px solid var(--line);padding-top:16px}
.disclaimer{max-width:var(--maxw);margin:14px auto 0;padding:0 20px;color:var(--muted);font-size:12px}

/* breadcrumb */
.crumbs{color:var(--muted);font-size:13px;margin:18px 0}
.crumbs a{color:var(--muted)}
.crumbs a:hover{color:var(--gold-soft)}

/* pagination */
.pager{display:flex;gap:8px;margin-top:26px;flex-wrap:wrap}
.pager a,.pager span{background:var(--panel);border:1px solid var(--line);padding:8px 14px;border-radius:9px;font-size:14px;color:var(--text-soft)}
.pager a:hover{border-color:var(--gold)}
.pager .current{background:var(--gold);color:#1a1405;border-color:var(--gold);font-weight:700}

/* empty */
.empty{text-align:center;padding:50px 0;color:var(--muted)}

/* ---------- hero background image ---------- */
.hero{overflow:hidden}
.hero-bg{position:absolute;inset:0;z-index:0}
.hero-bg img{width:100%;height:100%;object-fit:cover;opacity:.30}
.hero-bg::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(11,11,13,.70),rgba(20,19,15,.92))}
.hero .container{position:relative;z-index:2}

/* ---------- taxonomy INDEX (application/finish/etc.) ---------- */
.tax-group{padding:30px 0;border-bottom:1px solid var(--line)}
.tax-group:last-child{border-bottom:0}
.tax-head{display:flex;align-items:center;gap:18px;margin-bottom:20px}
.tax-banner{width:124px;height:84px;object-fit:cover;border-radius:12px;border:1px solid var(--line);flex:none}
.tax-head-txt h2{margin:0;font-size:22px;font-weight:800;letter-spacing:-.3px}
.tax-head-txt .sub{color:var(--muted);font-size:13.5px;margin-top:3px}
/* The origin's physical description, shown on the origin archive card. Kept
   narrow on purpose: it sits beside a thumbnail and has to read as a caption
   rather than compete with the product grid below it. */
.tax-head-txt .tax-note{color:var(--text-soft);font-size:13.5px;line-height:1.6;margin-top:9px;max-width:30em}
/* Origin archive hero: photograph beside the physical description.
 * Side by side rather than stacked, because the two say different things --
 * the image is what the material looks like, the text is why this origin
 * differs from the other six -- and a buyer reads them as a pair. */
.tax-hero{display:flex;gap:22px;align-items:flex-start;margin:0 0 26px;
  padding:18px;border:1px solid var(--line);border-radius:var(--radius);background:var(--panel)}
.tax-hero-img{width:280px;height:188px;object-fit:cover;border-radius:10px;flex:none;border:1px solid var(--line)}
.tax-hero-txt{flex:1;min-width:0}
.tax-hero-txt p{margin:0 0 10px;color:var(--text-soft);font-size:14px;line-height:1.7}
.tax-hero-txt p:last-child{margin-bottom:0}
@media(max-width:820px){.tax-hero{flex-direction:column}.tax-hero-img{width:100%;height:200px}}
@media(max-width:600px){.tax-head{flex-direction:column;align-items:flex-start}.tax-banner{width:100%;height:120px}}

/* ---------- China supply chain section ---------- */
.supply-chain .sc-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;margin-top:8px}
@media(max-width:980px){.supply-chain .sc-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.supply-chain .sc-grid{grid-template-columns:1fr}}
.sc-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:22px 20px;transition:transform .18s,border-color .18s,box-shadow .18s}
.sc-card:hover{transform:translateY(-4px);border-color:var(--gold);box-shadow:var(--shadow)}
.sc-ico{font-size:24px;width:48px;height:48px;border-radius:12px;display:grid;place-items:center;background:linear-gradient(135deg,var(--gold),var(--gold-deep));color:#1a1405;margin-bottom:14px}
.sc-card h3{margin:0 0 8px;font-size:17px}
.sc-card p{margin:0;color:var(--text-soft);font-size:14px}

/* china tag + note */
.tag-china{background:linear-gradient(135deg,rgba(201,168,106,.18),rgba(168,132,47,.10));border:1px solid var(--gold);color:var(--gold-soft);padding:4px 12px;border-radius:999px;font-size:12.5px;font-weight:600}
.tag-china.soft{background:var(--panel-2);border-color:var(--line);color:var(--muted);font-weight:500}
.china-note{color:var(--text-soft);font-size:14.5px;border-left:3px solid var(--gold);padding:4px 0 4px 14px;margin:14px 0}

/* About pillars */
.about-pillars{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin:26px 0}
@media(max-width:880px){.about-pillars{grid-template-columns:1fr}}
.about-pillar{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:20px}
.about-pillar h3{margin:0 0 8px;font-size:16.5px;color:var(--gold-soft)}
.about-pillar p{margin:0;color:var(--text-soft);font-size:14px}
.about-pillar code{background:var(--panel-2);border:1px solid var(--line);padding:1px 6px;border-radius:6px;color:var(--gold-soft);font-size:13px}

/* ---------- Social media icon module (footer) ---------- */
.social-wrap{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:22px;padding-top:18px;border-top:1px solid var(--line)}
.social-label{color:var(--muted);font-size:13.5px;letter-spacing:.3px}
.social-row{display:flex;gap:10px;flex-wrap:wrap}
.soc{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;background:var(--panel);border:1px solid var(--line);color:var(--text-soft);transition:transform .15s,border-color .15s,color .15s,background .15s}
.soc:hover{transform:translateY(-3px);border-color:var(--gold);color:var(--gold);background:linear-gradient(135deg,rgba(201,168,106,.15),rgba(168,132,47,.08))}
.soc-svg{width:20px;height:20px;fill:currentColor}
@media(max-width:600px){.social-wrap{justify-content:center}.social-label{width:100%;text-align:center}}

/* ensure hotlinked / asset images fill their frames */
img.ph-img, img.tax-banner{display:block;width:100%;height:100%;object-fit:cover}

/* ---------- Taxonomy INDEX per-term gallery (e.g. /application/) ---------- */
.tax-gallery{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:0 0 26px}
.tax-gallery-img{width:100%;height:172px;object-fit:cover;border-radius:12px;border:1px solid var(--line);transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease}
.tax-gallery-img:hover{transform:scale(1.02);border-color:var(--gold);box-shadow:var(--shadow)}
@media(max-width:600px){.tax-gallery{grid-template-columns:1fr}.tax-gallery-img{height:200px}}

/* ---------- Supplier verification block (single supplier) ---------- */
.verify-block{margin:18px 0 8px;background:linear-gradient(180deg,rgba(201,168,106,.08),rgba(201,168,106,.02));border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:12px;padding:16px 18px}
.vb-head{font-size:14px;font-weight:700;color:var(--gold-soft);letter-spacing:.3px;margin-bottom:12px;display:flex;align-items:center;gap:8px}
.vb-check{display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--gold);color:#1a1405;font-size:12px;font-weight:800}
.vb-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px 22px}
.vb-item.vb-full{grid-column:1 / -1}
.vb-k{font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);margin-bottom:2px}
.vb-v{font-size:14.5px;color:var(--text);font-weight:600}
@media(max-width:560px){.vb-grid{grid-template-columns:1fr}}

/* ---------- Verified badge (supplier cards) ---------- */
.card.supplier .thumb{position:relative}
.verified-badge{position:absolute;top:10px;left:10px;background:rgba(11,11,13,.82);border:1px solid var(--gold);color:var(--gold-soft);font-size:11px;font-weight:700;letter-spacing:.4px;padding:4px 9px;border-radius:20px}

/* ---------- Homepage trust strip ---------- */
.trust-strip .trust-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:18px}
.trust-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:20px 18px;transition:border-color .15s,transform .15s}
.trust-card:hover{border-color:var(--gold);transform:translateY(-3px)}
.t-ico{font-size:24px;margin-bottom:8px}
.trust-card h3{margin:0 0 6px;font-size:15.5px;color:var(--text)}
.trust-card p{margin:0;color:var(--text-soft);font-size:13.5px;line-height:1.5}
@media(max-width:880px){.trust-strip .trust-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:520px){.trust-strip .trust-grid{grid-template-columns:1fr}}

/* ================================================================
   MEMBERS · LOGIN · RFQ  (two-sided marketplace)
   ================================================================ */

/* ---------- auth (register / login) ---------- */
.auth-grid{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:start;padding:18px 0}
@media(max-width:900px){.auth-grid{grid-template-columns:1fr;gap:26px}}
.auth-intro h1{font-size:32px;margin:0 0 8px;letter-spacing:-.4px}
.auth-intro .sub{color:var(--muted);margin-bottom:22px;line-height:1.6}
/* Login / register secondary actions. Both sit on one rule so the filled
   Log in button stays the only primary control on the card. */
.auth-alt{
  margin:18px 0 0;padding-top:15px;
  border-top:1px solid var(--line);
  color:var(--muted);font-size:13.5px;
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
}
.auth-alt a,.auth-intro a{color:var(--gold-soft);text-decoration:none}
.auth-alt a:hover{text-decoration:underline}
.auth-alt .sep{color:var(--line)}

.role-switch{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:20px}
.role-switch a{
  background:var(--panel);border:1px solid var(--line);border-radius:13px;padding:16px 18px;
  display:flex;flex-direction:column;gap:4px;text-decoration:none;transition:border-color .2s,background .2s;
}
.role-switch a:hover{border-color:var(--gold)}
.role-switch a.on{border-color:var(--gold);background:rgba(201,168,106,.08)}
.rs-t{font-weight:700;font-size:16px;color:var(--text)}
.role-switch a.on .rs-t{color:var(--gold-soft)}
.rs-d{font-size:13px;color:var(--muted);line-height:1.4}
.role-perks{list-style:none;padding:0;margin:0 0 20px}
.role-perks li{color:var(--text-soft);font-size:14.5px;padding:7px 0 7px 24px;position:relative;line-height:1.5}
.role-perks li::before{content:"";position:absolute;left:0;top:14px;width:8px;height:8px;border-radius:2px;background:var(--gold)}
.notice.gate{background:rgba(201,168,106,.08);border:1px solid var(--gold);color:var(--text-soft);line-height:1.6}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:560px){.field-row{grid-template-columns:1fr}}
.field-inline{margin-bottom:20px}
.field .ck{display:flex;align-items:center;gap:9px;font-weight:400;cursor:pointer;margin:0}
.field .ck input{width:auto;accent-color:var(--gold)}
.fine{margin:14px 0 0;font-size:12.5px;color:var(--muted);line-height:1.5}
.fine a{color:var(--gold-soft)}

/* ---------- account shell ---------- */
.acct-head{display:flex;justify-content:space-between;align-items:flex-start;gap:18px;flex-wrap:wrap;margin-bottom:20px}
.acct-head h1{font-size:30px;margin:0 0 6px}
.acct-head .sub{margin:0;color:var(--muted)}
.acct-head-row{display:flex;justify-content:space-between;align-items:center;gap:14px;flex-wrap:wrap;margin:26px 0 16px}
.acct-head-row h3{margin:0}
.acct-badges{display:flex;gap:8px;flex-wrap:wrap}
.pill{font-size:12.5px;padding:5px 12px;border-radius:999px;border:1px solid var(--line);color:var(--text-soft);background:var(--panel-2)}
.pill.p-buy{border-color:var(--gold);color:var(--gold-soft)}
.pill.p-sup{border-color:var(--gold);color:var(--gold-soft)}
.pill.p-ok{border-color:var(--ok);color:#bff0cd}
.pill.p-wait{border-color:var(--gold);color:var(--gold-soft)}
.pill.p-no{border-color:var(--danger);color:#f3c4bc}
.pill.p-free{color:var(--muted)}

.acct-nav{display:flex;gap:8px;flex-wrap:wrap;margin:20px 0 26px;border-bottom:1px solid var(--line);padding-bottom:14px}
.acct-nav a{
  background:var(--panel);border:1px solid var(--line);border-radius:999px;
  padding:9px 16px;font-size:14px;color:var(--text-soft);text-decoration:none;
}
.acct-nav a:hover{border-color:var(--gold)}
.acct-nav a.active{background:var(--gold);color:#1a1405;border-color:var(--gold);font-weight:700}
.acct-nav a.out{margin-left:auto;color:var(--danger);border-color:var(--line)}
.acct-nav a.out:hover{border-color:var(--danger)}

.acct-grid{display:grid;grid-template-columns:1.2fr .8fr;gap:22px}
@media(max-width:880px){.acct-grid{grid-template-columns:1fr}}
.acct-card{background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:24px}
.acct-card h3{margin:0 0 14px}
.btn-link{
  display:inline-block;background:rgba(201,168,106,.1);border:1px solid var(--gold);
  color:var(--gold-soft);border-radius:10px;padding:11px 16px;font-size:14px;font-weight:600;text-decoration:none;
}
.btn-link:hover{background:var(--gold);color:#1a1405}
.empty{
  background:var(--panel);border:1px dashed var(--line);border-radius:14px;
  padding:34px;text-align:center;color:var(--muted);
}
.empty a{color:var(--gold-soft)}

/* ---------- RFQ board ---------- */
.rfq-item{
  background:var(--panel);border:1px solid var(--line);border-radius:14px;
  padding:20px 22px;margin-bottom:14px;
}
.rfq-item:hover{border-color:var(--gold)}
.rfq-item-t{font-size:18px;font-weight:700;color:var(--text);text-decoration:none;display:block;margin-bottom:6px;line-height:1.35}
.rfq-item-t:hover{color:var(--gold-soft)}
.rfq-meta{font-size:13px;color:var(--muted);margin-bottom:10px}
.rfq-tags{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px}
.rfq-tag{background:var(--panel-2);border:1px solid var(--line);border-radius:999px;padding:4px 12px;font-size:12.5px;color:var(--text-soft)}
.rfq-tag b{color:var(--gold-soft);font-weight:600}
.rfq-foot{font-size:12.5px;color:var(--muted);padding-top:4px;border-top:1px solid var(--line)}
.rfq-detail{font-size:15px;line-height:1.7;color:var(--text-soft);margin:16px 0}
.rfq-buyer{background:var(--panel-2);border:1px solid var(--line);border-radius:13px;padding:18px 20px;margin-top:22px}
.rfq-buyer h4{margin:0 0 8px}
.rfq-buyer p{margin:0 0 6px}
.small{font-size:13px;color:var(--muted);line-height:1.5}
.quote-box{background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:24px;position:sticky;top:20px}
.quote-box h4{margin:0 0 14px}
.quote-box.owned{border-color:var(--gold)}
.quote-box.sent{border-color:var(--ok)}
.quote-box .btn-link{margin-bottom:8px}

/* single-rfq uses existing .single-grid/.single */

/* ================================================================
   PRODUCT FORM ATLAS  (/form/ 8 groups -> 69 forms)
   ================================================================ */
.form-groups{display:flex;flex-direction:column;gap:14px;margin:26px 0 10px}

.fg{
  background:var(--panel);border:1px solid var(--line);border-radius:16px;
  padding:18px 20px;transition:border-color .2s;
}
.fg:hover{border-color:var(--gold)}

.fg-head{
  display:flex;align-items:center;gap:14px;text-decoration:none;
  padding-bottom:12px;margin-bottom:12px;border-bottom:1px solid var(--line);
}
.fg-key{
  flex:0 1 auto;min-width:34px;max-width:46%;height:34px;border-radius:9px;
  padding:0 6px;
  background:rgba(201,168,106,.14);border:1px solid var(--gold);
  color:var(--gold-soft);font-weight:700;font-size:15px;
  line-height:32px;text-align:center;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.fg-titles{flex:1 1 auto;display:flex;flex-direction:column;gap:2px;min-width:0}
.fg-cn{font-size:17px;font-weight:700;color:var(--text)}
.fg-head:hover .fg-cn{color:var(--gold-soft)}
.fg-en{font-size:12.5px;color:var(--muted);letter-spacing:.2px}
.fg-count{
  flex:0 0 auto;font-size:12.5px;color:var(--gold-soft);
  background:rgba(201,168,106,.1);border:1px solid var(--line);
  border-radius:999px;padding:5px 12px;white-space:nowrap;
}

.fg-forms{display:flex;flex-wrap:wrap;gap:8px}
.fg-chip{
  display:inline-flex;align-items:center;
  background:var(--panel-2);border:1px solid var(--line);border-radius:999px;
  padding:7px 14px;font-size:13.5px;color:var(--text-soft);
  text-decoration:none;transition:all .18s;
}
.fg-chip:hover{border-color:var(--gold);color:var(--gold-soft);transform:translateY(-1px)}
.fg-chip.is-p0{border-color:rgba(201,168,106,.55);color:var(--gold-soft);font-weight:600}
.fg-chip.is-p1{color:var(--text)}

/* group landing page: spec tiles */
.form-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));
  gap:14px;margin:24px 0 8px;
}
.form-card-tile{
  display:flex;flex-direction:column;gap:7px;
  background:var(--panel);border:1px solid var(--line);border-radius:14px;
  padding:18px 18px 16px;text-decoration:none;transition:all .2s;
}
.form-card-tile:hover{border-color:var(--gold);transform:translateY(-3px);box-shadow:var(--shadow)}
.form-card-tile.is-p0{border-color:rgba(201,168,106,.5)}
.ft-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.form-card-tile h3{margin:0;font-size:16.5px;line-height:1.35;color:var(--text)}
.form-card-tile:hover h3{color:var(--gold-soft)}
.ft-badge{
  flex:0 0 auto;font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;
  color:#1a1405;background:var(--gold);border-radius:999px;padding:3px 9px;font-weight:700;
}
.ft-en{font-size:12.5px;color:var(--muted);letter-spacing:.2px}
.ft-spec{
  font-size:12.5px;color:var(--text-soft);line-height:1.5;
  background:var(--panel-2);border:1px solid var(--line);
  border-radius:9px;padding:8px 10px;
}
.ft-fin{font-size:12px;color:var(--muted);line-height:1.45}
.ft-fin b,.ft-uses b{color:var(--gold-soft);font-weight:600}
.ft-uses{font-size:12px;color:var(--gold-soft);opacity:.85;margin-top:auto;padding-top:4px}

@media(max-width:640px){
  .fg-head{flex-wrap:wrap;gap:10px}
  .fg-count{order:3}
}

/* ---------- single product-form page (/form/<slug>/) ---------- */
.spec-blocks{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
  gap:14px;margin:24px 0 8px;
}
.spec-block{
  background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:18px 20px;
}
.spec-block h4{
  margin:0 0 10px;font-size:12.5px;letter-spacing:.8px;text-transform:uppercase;
  color:var(--gold-soft);font-weight:600;
}
.spec-block p{margin:0;font-size:14.5px;color:var(--text-soft);line-height:1.65}
.spec-block .tagrow{margin:0}
.spec-block .tagrow a,.spec-block .tagrow span{
  background:var(--panel-2);border:1px solid var(--line);
  padding:5px 12px;border-radius:999px;font-size:13px;color:var(--text-soft);text-decoration:none;
}
.spec-block .tagrow a:hover{border-color:var(--gold);color:var(--gold-soft)}

/* ================================================================
   POST YOUR NEEDS  (/post-your-needs/  buyer landing page)
   ================================================================ */
.btn-lg{padding:14px 24px;font-size:15.5px;border-radius:12px}

/* hero */
.need-hero{
  background:linear-gradient(140deg,rgba(201,168,106,.10),rgba(201,168,106,.02) 55%);
  border:1px solid var(--line);border-radius:20px;
  padding:32px 34px;margin:26px 0 8px;
}
.need-hero-in{display:grid;grid-template-columns:1.55fr .75fr;gap:34px;align-items:start}
@media(max-width:880px){.need-hero{padding:24px 20px}.need-hero-in{grid-template-columns:1fr;gap:22px}}
.need-hero .kicker{
  display:inline-block;font-size:11.5px;letter-spacing:1.2px;text-transform:uppercase;
  color:var(--gold-soft);border:1px solid var(--line);border-radius:999px;
  padding:4px 12px;margin-bottom:14px;
}
.need-hero h1{font-size:38px;margin:0 0 12px;letter-spacing:-.6px;line-height:1.1}
@media(max-width:560px){.need-hero h1{font-size:30px}}
.need-hero-txt > p{color:var(--text-soft);font-size:15.5px;line-height:1.75;margin:0 0 20px;max-width:30em}

.need-points{list-style:none;margin:0;padding:0;display:grid;gap:9px}
.need-points li{
  position:relative;padding:6px 0 6px 26px;
  font-size:14.5px;color:var(--text-soft);line-height:1.55;
}
.need-points li::before{
  content:"";position:absolute;left:0;top:14px;width:9px;height:9px;
  border-radius:3px;background:var(--gold);
}
.need-points b{color:var(--text);font-weight:600}

.need-hero-side{
  display:grid;gap:10px;background:var(--panel);
  border:1px solid var(--line);border-radius:15px;padding:20px;
}
.need-stat{display:flex;flex-direction:column;gap:3px;padding-bottom:10px;border-bottom:1px solid var(--line)}
.need-stat:last-child{padding-bottom:0;border-bottom:0}
.need-stat .l{font-size:11.5px;letter-spacing:.9px;text-transform:uppercase;color:var(--muted)}
.need-stat .v{font-size:14.5px;color:var(--text);font-weight:600}

/* body layout */
.need-body{display:grid;grid-template-columns:1.5fr .7fr;gap:30px;align-items:start;margin:30px 0 20px}
@media(max-width:900px){.need-body{grid-template-columns:1fr;gap:26px}}
.need-main h2{font-size:25px;margin:0 0 8px}
.need-sub{color:var(--muted);font-size:14.5px;line-height:1.7;margin:0 0 20px;max-width:30em}
.need-form .field-row{margin-bottom:0}

.notice.ok{background:rgba(120,200,140,.1);border:1px solid var(--ok);color:#cdeed4}
.notice.ok a{color:#e6ffed;text-decoration:underline}

/* sidebar */
.need-side{
  background:var(--panel);border:1px solid var(--line);
  border-radius:16px;padding:24px;
}
.need-side h3{font-size:13px;letter-spacing:1px;text-transform:uppercase;color:var(--gold-soft);margin:0 0 14px}
.need-side h3.mt{margin-top:28px;padding-top:22px;border-top:1px solid var(--line)}
.need-steps{margin:0 0 4px;padding-left:20px;display:grid;gap:11px}
.need-steps li{font-size:14px;color:var(--text-soft);line-height:1.6}
.need-steps li::marker{color:var(--gold);font-weight:700}
.need-steps b{color:var(--text)}
.need-side-p{font-size:13.5px;color:var(--muted);line-height:1.6;margin:0 0 12px}
.need-groups{list-style:none;margin:0 0 14px;padding:0;display:grid;gap:6px}
.need-groups a{
  display:block;font-size:14px;color:var(--text-soft);
  text-decoration:none;padding:7px 11px;border-radius:9px;
  background:var(--panel-2);border:1px solid var(--line);transition:all .16s;
}
.need-groups a:hover{border-color:var(--gold);color:var(--gold-soft);transform:translateX(2px)}

/* ================================================================
   OUR SUPPLY  (/supply-chain/) — replaces the old supplier directory
   ================================================================ */
.sc-hero{
  background:linear-gradient(140deg,rgba(201,168,106,.10),rgba(201,168,106,.02) 55%);
  border:1px solid var(--line);border-radius:20px;padding:34px 36px;margin:26px 0 8px;
}
.sc-hero .kicker{
  display:inline-block;font-size:11.5px;letter-spacing:1.2px;text-transform:uppercase;
  color:var(--gold-soft);border:1px solid var(--line);border-radius:999px;
  padding:4px 12px;margin-bottom:14px;
}
.sc-hero h1{font-size:36px;margin:0 0 14px;letter-spacing:-.5px;line-height:1.15}
.sc-hero p{color:var(--text-soft);font-size:16px;line-height:1.75;margin:0;max-width:30em}
@media(max-width:560px){.sc-hero{padding:24px 20px}.sc-hero h1{font-size:28px}}

.sc-chain{display:grid;grid-template-columns:repeat(2,1fr);gap:18px;margin:30px 0 10px}
@media(max-width:880px){.sc-chain{grid-template-columns:1fr}}
.sc-step{
  background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:26px 26px 24px;
  position:relative;transition:border-color .2s;
}
.sc-step:hover{border-color:var(--gold)}
.sc-step .n{
  display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;border-radius:9px;margin-bottom:12px;
  background:rgba(201,168,106,.14);border:1px solid var(--gold);
  color:var(--gold-soft);font-weight:700;font-size:13px;
}
.sc-step h3{margin:0 0 10px;font-size:19px}
.sc-step p{margin:0 0 12px;color:var(--text-soft);font-size:14.5px;line-height:1.7}
.sc-step ul{list-style:none;margin:0;padding:0;display:grid;gap:7px}
.sc-step li{
  position:relative;padding:3px 0 3px 20px;
  font-size:14px;color:var(--muted);line-height:1.6;
}
.sc-step li::before{
  content:"";position:absolute;left:0;top:11px;width:7px;height:7px;
  border-radius:2px;background:var(--gold);opacity:.8;
}

.sc-specs,.sc-forms,.sc-cta{margin:40px 0 10px}
.sc-specs h2,.sc-forms h2,.sc-cta h2{font-size:26px;margin:0 0 8px}
.sc-sub{color:var(--muted);font-size:14.5px;line-height:1.7;margin:0 0 20px;max-width:30em}
.sc-more{margin:16px 0 0}

/* The stance line — the one sentence that answers "whose side are you on?".
   It sits first in the hero paragraph and must be visually dominant. */
.stance{
  display:block;
  color:var(--gold-soft);
  font-weight:600;
  font-size:16px;
  letter-spacing:.1px;
  margin-bottom:10px;
}
.hero .lead .stance{font-size:17px}

/* ================================================================
   CONTACT — email + WhatsApp, single source: TMQ_EMAIL / TMQ_WHATSAPP
   ================================================================ */

/* --- shared strip --- */
.contact-strip{display:flex;flex-wrap:wrap;gap:10px 18px;align-items:center}
.contact-strip .cs-item{
  display:inline-flex;align-items:center;gap:9px;
  text-decoration:none;font-size:14.5px;color:var(--text-soft);
  border:1px solid var(--line);border-radius:10px;padding:9px 15px;
  background:var(--panel-2);transition:border-color .16s,color .16s,background .16s;
}
.contact-strip .cs-item:hover{border-color:var(--gold);color:var(--gold-soft)}
.contact-strip .cs-txt{white-space:nowrap}

/* envelope icon */
.contact-strip .cs-mail .cs-ico{
  width:16px;height:16px;flex:0 0 auto;position:relative;
  border:1.6px solid currentColor;border-radius:3px;
}
.contact-strip .cs-mail .cs-ico::after{
  content:"";position:absolute;left:1.6px;top:1.6px;width:9px;height:9px;
  border-top:1.6px solid currentColor;border-right:1.6px solid currentColor;
  transform:rotate(45deg) skew(8deg,8deg);
}
/* whatsapp glyph: rounded square with a phone hook */
.contact-strip .cs-wa .cs-ico{
  width:16px;height:16px;flex:0 0 auto;border-radius:50%;
  border:1.6px solid #25D366;position:relative;
}
.contact-strip .cs-wa .cs-ico::before{
  content:"";position:absolute;left:4.6px;top:3.2px;width:6px;height:8px;
  border-left:1.8px solid #25D366;border-bottom:1.8px solid #25D366;
  border-bottom-left-radius:3px;transform:rotate(-12deg);
}
.contact-strip .cs-wa:hover{border-color:#25D366;color:#25D366}

/* --- footer block --- */
.footer-contact{
  display:flex;align-items:center;justify-content:space-between;gap:26px;flex-wrap:wrap;
  background:var(--panel);border:1px solid var(--line);border-radius:16px;
  padding:22px 26px;margin:26px 0 4px;
}
.footer-contact .fc-l h4{margin:0 0 5px;font-size:13px;letter-spacing:1px;text-transform:uppercase;color:var(--gold-soft)}
.footer-contact .fc-l p{margin:0;font-size:14px;color:var(--muted);line-height:1.55;max-width:30em}

/* --- quote page (under the form) --- */
.need-alt{margin-top:22px;padding-top:20px;border-top:1px solid var(--line)}
.need-alt-t{margin:0 0 12px;font-size:14.5px;color:var(--muted)}

/* --- services page (in CTA) --- */
.contact-strip.in-cta{margin-bottom:18px;justify-content:flex-start}

/* --- header WhatsApp link --- */
.nav-wa{
  display:inline-flex;align-items:center;gap:7px;
  color:#25D366;text-decoration:none;font-size:13.5px;font-weight:600;
  padding:5px 10px;border-radius:9px;border:1px solid transparent;
  white-space:nowrap;transition:background .16s,border-color .16s;
}
.nav-wa:hover{background:rgba(37,211,102,.10);border-color:rgba(37,211,102,.45)}
.nav-wa .wa-ico{
  width:15px;height:15px;flex:0 0 auto;border-radius:50%;
  border:1.6px solid #25D366;position:relative;
}
.nav-wa .wa-ico::before{
  content:"";position:absolute;left:4.4px;top:3px;width:5.6px;height:7.4px;
  border-left:1.7px solid #25D666;border-bottom:1.7px solid #25D666;
  border-bottom-left-radius:3px;transform:rotate(-12deg);
}
@media(max-width:560px){.nav-wa .wa-txt{display:none}.nav-wa{padding:6px 8px}}

@media(max-width:760px){
  .footer-contact{flex-direction:column;align-items:flex-start;gap:16px}
  .contact-strip{width:100%}
  .contact-strip .cs-item{flex:1 1 auto;justify-content:center}
}

/* ================================================================
   OUR CAPABILITY  (/capability/)
   The soft-power proof: workshop, machines, people, numbers, timeline,
   and the limits we do not cross. Visual language deliberately matches
   /supply-chain/ so the two pages read as one system.
   ================================================================ */
.cap-hero{
  background:linear-gradient(140deg,rgba(201,168,106,.10),rgba(201,168,106,.02) 55%);
  border:1px solid var(--line);border-radius:20px;padding:34px 36px;margin:26px 0 8px;
}
.cap-hero .kicker{
  display:inline-block;font-size:11.5px;letter-spacing:1.2px;text-transform:uppercase;
  color:var(--gold-soft);border:1px solid var(--line);border-radius:999px;
  padding:4px 12px;margin-bottom:14px;
}
.cap-hero h1{font-size:36px;margin:0 0 14px;letter-spacing:-.5px;line-height:1.15}
.cap-hero p{color:var(--text-soft);font-size:16px;line-height:1.75;margin:0;max-width:30em}
@media(max-width:560px){.cap-hero{padding:24px 20px}.cap-hero h1{font-size:28px}}

.cap-block{margin:42px 0 10px}
.cap-n{
  display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;border-radius:9px;margin-bottom:12px;
  background:rgba(201,168,106,.14);border:1px solid var(--gold);
  color:var(--gold-soft);font-weight:700;font-size:13px;
}
.cap-head h2{font-size:26px;margin:0 0 8px}
.cap-sub{color:var(--muted);font-size:14.5px;line-height:1.7;margin:0 0 20px;max-width:30em}

/* --- 01 workshop: text beside image --- */
.cap-split{display:grid;grid-template-columns:1.15fr .85fr;gap:26px;align-items:start}
@media(max-width:880px){.cap-split{grid-template-columns:1fr;gap:20px}}
.cap-split-txt h2{font-size:26px;margin:0 0 14px}
.cap-split-txt p{margin:0 0 12px;color:var(--text-soft);font-size:14.5px;line-height:1.75}
.cap-split-txt strong{color:var(--gold-soft);font-weight:600}
.cap-list{list-style:none;margin:16px 0 0;padding:0;display:grid;gap:8px}
.cap-list li{position:relative;padding:3px 0 3px 22px;font-size:14px;color:var(--muted);line-height:1.6}
.cap-list li::before{
  content:"";position:absolute;left:0;top:11px;width:7px;height:7px;
  border-radius:2px;background:var(--gold);opacity:.8;
}
.cap-split-img{position:relative}
.cap-img{
  width:100%;border-radius:16px;border:1px solid var(--line);
  aspect-ratio:4/3;object-fit:cover;
  max-height:400px;
}
.cap-cap{
  display:block;margin-top:9px;font-size:12.5px;color:var(--muted);line-height:1.5;
}

/* --- 02 machines / 03 people / 06 never-do: 3-up cards --- */
.cap-machines,.cap-roles,.cap-never{
  display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:6px;
}
@media(max-width:880px){.cap-machines,.cap-roles,.cap-never{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.cap-machines,.cap-roles,.cap-never{grid-template-columns:1fr}}
.cap-machine,.cap-role,.cap-never-item{
  background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:22px 22px 20px;
  transition:border-color .2s;
}
.cap-machine:hover,.cap-role:hover,.cap-never-item:hover{border-color:var(--gold)}
.cap-machine h4,.cap-role h4,.cap-never-item h4{
  margin:0 0 8px;font-size:16.5px;color:var(--gold-soft);
}
.cap-machine p,.cap-role p,.cap-never-item p{
  margin:0;color:var(--text-soft);font-size:14px;line-height:1.7;
}

/* --- 04 numbers --- */
.cap-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:6px}
@media(max-width:880px){.cap-stats{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.cap-stats{grid-template-columns:1fr}}
.cap-stat{
  background:var(--panel);border:1px solid var(--line);border-radius:16px;
  padding:22px 22px 20px;display:flex;flex-direction:column;gap:5px;
  transition:border-color .2s;
}
.cap-stat:hover{border-color:var(--gold)}
.cap-stat .v{
  font-size:32px;line-height:1.05;color:var(--gold-soft);letter-spacing:-.5px;font-weight:700;
}
.cap-stat .k{font-size:14.5px;color:var(--text)}
.cap-stat .n{font-size:12.5px;color:var(--muted);line-height:1.55}
.cap-fine{
  margin:20px 0 0;font-size:13.5px;color:var(--muted);line-height:1.7;
  border-left:2px solid var(--line);padding-left:14px;max-width:30em;
}

/* --- 05 timeline --- */
.cap-track{display:grid;grid-template-columns:repeat(5,1fr);gap:14px;margin-top:6px}
@media(max-width:1000px){.cap-track{grid-template-columns:repeat(2,1fr)}}
@media(max-width:600px){.cap-track{grid-template-columns:1fr}}
.cap-day{
  background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:20px 20px 18px;
  position:relative;transition:border-color .2s;
}
.cap-day:hover{border-color:var(--gold)}
.cap-day .d{
  display:inline-block;margin-bottom:10px;padding:3px 10px;border-radius:999px;
  background:rgba(201,168,106,.14);border:1px solid var(--gold);
  color:var(--gold-soft);font-size:12px;font-weight:700;letter-spacing:.3px;
}
.cap-day h4{margin:0 0 8px;font-size:16px}
.cap-day p{margin:0;color:var(--text-soft);font-size:13.5px;line-height:1.65}
/* ================================================================
   REQUEST A SAMPLE  (/sample-request/)
   The second buyer entry point. Reuses .need-* for the form layout so
   it reads as one system with /post-your-needs/; only the hero and the
   sample-specific bits are new.
   ================================================================ */
.smp-hero{
  background:linear-gradient(140deg,rgba(201,168,106,.10),rgba(201,168,106,.02) 55%);
  border:1px solid var(--line);border-radius:20px;padding:34px 36px;margin:26px 0 8px;
}
.smp-hero .kicker{
  display:inline-block;font-size:11.5px;letter-spacing:1.2px;text-transform:uppercase;
  color:var(--gold-soft);border:1px solid var(--line);border-radius:999px;
  padding:4px 12px;margin-bottom:14px;
}
.smp-hero h1{font-size:38px;margin:0 0 12px;letter-spacing:-.6px;line-height:1.1}
.smp-hero p{color:var(--text-soft);font-size:15.5px;line-height:1.75;margin:0;max-width:30em}
@media(max-width:560px){.smp-hero{padding:24px 20px}.smp-hero h1{font-size:29px}}

/* contact strip inside the sample sidebar */
.need-side .contact-strip{margin-top:16px}
.need-side .contact-strip .cs-item{font-size:13.5px;padding:8px 13px}
/* checkbox rows: .field supplies the spacing, keep the list compact */
.need-form .field .ck{margin-bottom:6px}

/* Footer now carries three columns, not four: the top nav owns the catalogue
   so the footer only lists company, specification and account.
   .cols is a flex row, so give each third a floor and let them wrap. */
.cols-3 > div{flex:1 1 260px;min-width:0}
@media(max-width:640px){
  .cols-3{gap:28px}
  .cols-3 > div{flex:1 1 100%}
}

/* ================================================================
   DOWNLOAD CENTRE  (/download/)
   Cards, not a filing column. Each card carries the file's own first
   page as its face so a buyer can see what they are about to download.
   Grid is CSS grid with auto-fit, so three files look like three cards
   rather than three full-width bars. Gating stays server-side in dl/.
   ================================================================ */
.dl-head{margin:30px 0 0}
.dl-head h1{font-size:34px;margin:0 0 10px;letter-spacing:-.5px;line-height:1.1}
/* The sub-headline is the stone's own sentence about which documents it
   publishes. It sits between the H1 and the access line, and it is the part
   that differs between sites -- before this existed the page said the same
   forty words on all three domains. */
.dl-sub{margin:0 0 14px;font-size:15.5px;line-height:1.62;color:var(--text-soft);max-width:30em}
.dl-open{margin:0;font-size:14.5px;color:var(--muted);line-height:1.6}
.dl-open a{color:var(--gold-soft)}

/* Empty state.
   An empty library is not a dead end if the visitor has a way out of it, so
   the state carries the two actions that actually move the enquiry forward:
   a sample, and a specification. Both were absent before, which left the page
   reporting an absence and nothing else. */
.dl-empty{margin:26px 0 0;padding:22px 0 0;border-top:1px solid var(--line)}
.dl-empty .dl-open{max-width:30em}
.dl-empty-act{margin:16px 0 0;display:flex;flex-wrap:wrap;gap:10px}
.dl-empty-act .btn{min-height:44px}
@media(max-width:560px){
  .dl-head h1{font-size:27px}
  .dl-empty-act .btn{width:100%}
}

/* auto-fit + minmax: the card count decides the columns, and a single file
   does not stretch across the whole page the way a flex row would. */
.dl-grid{
  list-style:none;margin:30px 0 0;padding:0;
  display:grid;gap:20px;
  grid-template-columns:repeat(auto-fit,minmax(268px,1fr));
}

.dl-card{
  display:flex;flex-direction:column;
  background:var(--panel,#141310);
  border:1px solid var(--line);border-radius:12px;
  overflow:hidden;
  transition:border-color .16s ease,transform .16s ease;
}
.dl-card:hover{border-color:rgba(201,168,106,.42);transform:translateY(-2px)}

/* face: a fixed-ratio window onto the document itself */
.dl-face{
  position:relative;
  aspect-ratio:4/3;
  background:#0e0e0c;
  display:flex;align-items:center;justify-content:center;
  overflow:hidden;
  border-bottom:1px solid var(--line);
}
.dl-face img{width:100%;height:100%;object-fit:cover;display:block}
/* No cover available: a quiet type block, not a broken-image icon. */
.dl-face-fallback{
  /* ⛔ ON A NEAR-BLACK CARD FACE.
     The face behind this type block is #0e0e0c, so the paper station's muted
     grey measured 2.98:1 on it -- the word "PDF" was a smudge. The face is
     deliberately dark (it stands in for a cover), so the type on it is
     light. */
  font-size:26px;letter-spacing:2px;color:#CFC9BC;opacity:.85;font-weight:600;
}
.dl-badge{
  position:absolute;top:10px;left:10px;
  font-size:10px;letter-spacing:.9px;text-transform:uppercase;font-weight:600;
  padding:4px 9px;border-radius:4px;
  /* ⛔ THE BADGE IS A DARK CHIP ON A DARK COVER.
     Gold-soft on it measured 3.32:1 at 10px. The chip is dark, so the
     label on it is light. */
  background:rgba(14,14,12,.82);color:#E8E4DA;
  border:1px solid rgba(201,168,106,.4);
  backdrop-filter:blur(4px);
}
.dl-badge.is-member{color:#CFC9BC;border-color:var(--line);border-style:dashed}

.dl-body{flex:1;padding:16px 17px 6px}
.dl-name{
  margin:0;font-size:15.5px;line-height:1.42;color:var(--text);font-weight:600;
}
.dl-card.is-member .dl-name{color:var(--text-soft)}
.dl-desc{
  margin:8px 0 0;font-size:13.5px;line-height:1.55;color:var(--muted);
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
}
.dl-meta{
  margin:10px 0 0;font-size:12px;letter-spacing:.3px;color:var(--muted);opacity:.85;
}

.dl-act{padding:6px 17px 17px}
.dl-go{
  display:block;text-align:center;
  font-size:13px;font-weight:600;text-decoration:none;line-height:1.4;
  padding:9px 16px;border-radius:7px;white-space:nowrap;
  background:linear-gradient(135deg,var(--gold),var(--gold-deep));color:#1a1405;
  transition:filter .15s ease;
}
.dl-go:hover{filter:brightness(1.08);color:#1a1405}
.dl-go.is-lock{
  background:transparent;border:1px solid var(--line);
  color:var(--gold-soft);font-weight:500;
}
.dl-go.is-lock:hover{border-color:var(--gold)}
.dl-go.is-soon{
  background:transparent;border:1px dashed var(--line);
  color:var(--muted);font-weight:400;
}

@media(max-width:560px){
  /* One column by default on a phone; the face keeps its ratio so the page
     still reads as a set of documents rather than a list. */
  .dl-grid{grid-template-columns:1fr;gap:16px}
  .dl-face{aspect-ratio:16/10}
}

/* ================================================================
   PRODUCT GALLERY + IMAGE VIEWER  (single-product.php)
   A stone buyer reads a photograph rather than glancing at it, so
   the set matters: one picture per product was hiding the edge,
   the back and the veining. The main frame is a button because it
   opens the full-size file, and the hint says so - an affordance
   nobody can guess is an affordance nobody uses.
   ================================================================ */
.gallery{display:grid;gap:12px}

/* main frame */
.gallery .main{
  position:relative;display:block;width:100%;padding:0;margin:0;
  border-radius:14px;overflow:hidden;border:1px solid var(--line);
  aspect-ratio:4/3;background:var(--panel-2);
  cursor:zoom-in;font:inherit;
}
.gallery .main img{width:100%;height:100%;object-fit:cover;display:block}
.gallery .main:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.tmq-zoom-hint{
  position:absolute;right:10px;bottom:10px;
  font-size:11px;letter-spacing:.4px;
  padding:5px 10px;border-radius:20px;
  background:rgba(14,14,12,.72);color:var(--gold-soft);
  border:1px solid rgba(201,168,106,.34);
  opacity:0;transition:opacity .16s ease;
}
.gallery .main:hover .tmq-zoom-hint,
.gallery .main:focus-visible .tmq-zoom-hint{opacity:1}

/* ---------- the rail ----------
   Two and a half pictures at a time, the rest one swipe away. A single large
   frame with a thumbnail strip underneath makes a visitor assemble a mental
   picture of the product by clicking through it one photograph at a time;
   showing a row means the comparison - face against edge, daylight against
   lamplight - happens without any interaction at all.

   Slides are a fixed share of the track rather than a fixed width, so the same
   markup gives two-up on a phone and three-up on a desktop without a
   breakpoint per count.

   align-items:start matters more than it looks. .gallery is a grid, and a grid
   stretches its children to the tallest row by default; the caption line under
   the rail was being pulled to the height of the specification column beside it,
   which left a block of dead space under the pictures. */
.gallery{display:grid;gap:12px;align-items:start}
.tmq-rail{position:relative}
.tmq-rail-track{
  display:flex;gap:14px;
  overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:none;
  padding-bottom:2px;
  cursor:grab;
}
.tmq-rail-track::-webkit-scrollbar{display:none}
.tmq-rail-track.is-dragging{cursor:grabbing;scroll-snap-type:none}
.tmq-rail-track:focus-visible{outline:2px solid var(--gold);outline-offset:4px;border-radius:10px}

.tmq-slide{
  position:relative;margin:0;flex:0 0 auto;
  /* 2.4 per view mirrors the reference site: never quite three, so the rail
     visibly continues and the visitor knows there is more. */
  width:calc((100% - 28px)/2.4);
  aspect-ratio:4/3;
  border-radius:12px;overflow:hidden;
  border:1px solid var(--line);background:var(--panel-2);
  scroll-snap-align:start;
  cursor:zoom-in;
}
.tmq-slide img{width:100%;height:100%;object-fit:cover;display:block}
.tmq-slide figcaption{
  position:absolute;left:0;right:0;bottom:0;
  padding:26px 10px 8px;
  font-size:11.5px;line-height:1.4;color:var(--text-soft);
  background:linear-gradient(to top,rgba(10,10,9,.9),rgba(10,10,9,0));
  pointer-events:none;
}

/* ⛔ THE CAPTION IS ON A DARK GRADIENT, SO IT CANNOT BE --text-soft.
 *
 * This rule came from the fourth station, where the ground is dark and
 * --text-soft is a pale colour — a light caption on a dark gradient, and
 * it reads.
 *
 * ⛔ AND THIS STATION IS THE OTHER WAY ROUND. Its ground is paper and its
 * --text-soft is a dark grey (#3A362F), so the caption became dark grey
 * on a 90%-black gradient: about 1.1:1, which is to say invisible. The
 * picture looked like it had no caption at all, which is what a caption
 * that is technically present and practically unreadable looks like.
 *
 * ⛔ AND IT IS THE SAME CLASS OF FAULT AS P078: a variable that means
 * "a readable colour" on one station means "the ground's soft text
 * colour" on another, and the value that was right on the fourth station
 * is wrong here.
 *
 * ⛔ AND THE OVERRIDE IS A SEPARATE SELECTOR ON PURPOSE.
 * The first version put the light colour inside the original rule block,
 * as a second `color` declaration. LiteSpeed's CSS combiner took the
 * whole block and the second declaration did not survive it — the
 * merged file carried the original `color:var(--text-soft)` and the
 * override was gone, with no error anywhere.
 *
 * A combiner that keeps one rule per selector means an override has to
 * be a DIFFERENT selector, so that it is a different rule. Hence
 * `body.trz .tmq-slide figcaption` — the same element, reached through
 * the station's own body class, which no other station's file has.
 *
 * #E8E4DC on rgba(10,10,9,.9) is about 14:1.
 */
body.trz .tmq-slide figcaption{color:#E8E4DC}

.tmq-slide:hover{border-color:rgba(201,168,106,.45)}
.tmq-slide .tmq-zoom-hint{right:8px;bottom:8px}

/* Arrows sit outside the track so they never cover a picture. They are
   hidden by markup until the script proves there is somewhere to go. */
.tmq-rail-nav{
  position:absolute;top:50%;transform:translateY(-50%);
  z-index:2;
  width:40px;height:40px;display:flex;align-items:center;justify-content:center;
  font-size:24px;line-height:1;
  color:var(--gold-soft);background:rgba(16,16,14,.9);
  border:1px solid var(--line);border-radius:50%;
  cursor:pointer;transition:color .15s ease,border-color .15s ease;
}
.tmq-rail-nav:hover{color:var(--gold);border-color:var(--gold)}
.tmq-rail-nav:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.tmq-rail-nav[hidden]{display:none}
.tmq-rail-nav.is-prev{left:-6px}
.tmq-rail-nav.is-next{right:-6px}

.tmq-rail-bar{
  display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;
  margin:10px 0 0;font-size:12px;color:var(--muted);
}
.tmq-rail-count{letter-spacing:1px;color:var(--gold-soft);font-weight:600}
.tmq-rail-tip{opacity:.7}

@media(max-width:900px){
  .tmq-slide{width:calc((100% - 14px)/1.6)}
  /* ⛔ THE ARROW BUTTONS ARE REMOVED BELOW 900px, NOT MOVED INWARD.
     They sat at left/right:-4px, which is what pushed the page 4px wider than
     the phone: after the grid fix this was the only overflow left on the
     product pages, and it came from a control that is worth less than the
     width it costs.
     ⛔ On a touch screen the pictures are swiped, not clicked — the arrow is a
     pointer affordance for a mouse. And the rail already scrolls, so nothing
     becomes unreachable by removing it. */
  .tmq-rail-nav{display:none}
}
@media(max-width:560px){
  /* One and a half on a phone: enough to see that the face and the edge
     differ, without leaving a sliver too narrow to read. */
  .tmq-slide{width:78%}
  .tmq-slide figcaption{display:none}
  .tmq-rail-tip{display:none}
}

/* ---------- the overlay ---------- */
.tmq-lb{
  position:fixed;inset:0;z-index:9999;
  display:none;
  background:rgba(8,8,7,.96);
  padding:clamp(14px,3vw,40px);
  grid-template-rows:1fr auto auto auto;
  justify-items:center;align-items:center;
}
.tmq-lb.is-open{display:grid}
/* Scroll lock while the lightbox is open.
   Both elements are locked, not just the body. The scrolling box on a desktop
   browser is the root element, so body{overflow:hidden} on its own left the
   page fully scrollable behind the picture -- measured at 428px of scroll
   while the overlay was open, which is how a viewer ends up looking at a
   black rectangle and the page they had already scrolled away from. */
html.tmq-lb-open,body.tmq-lb-open{overflow:hidden}
/* Compensate for the scrollbar so the page does not shift sideways on close. */
html.tmq-lb-open{scrollbar-width:none}
html.tmq-lb-open::-webkit-scrollbar{display:none}

.tmq-lb-stage{
  grid-row:1;width:100%;height:100%;
  display:flex;align-items:center;justify-content:center;
  overflow:hidden;cursor:zoom-in;min-height:0;
}
.tmq-lb-stage img{
  max-width:100%;max-height:100%;
  object-fit:contain;
  border-radius:6px;
  transition:transform .18s ease;
  transform-origin:center center;
}
.tmq-lb.is-zoomed .tmq-lb-stage{cursor:zoom-out}

/* Controls sized in vmin so they stay reachable on a phone and do not
   dwarf the picture on a desktop monitor.
   The floor is 44px, not 38: both Apple and Google specify 44px as the
   minimum comfortable touch target, and a close button measured at 38x38 on an
   iPhone viewport meant the hardest thing to hit on the screen was the one
   control a visitor has to find to get out. */
.tmq-lb-close,.tmq-lb-nav{
  position:absolute;z-index:2;
  width:clamp(44px,4.4vmin,52px);height:clamp(44px,4.4vmin,52px);
  display:flex;align-items:center;justify-content:center;
  font-size:clamp(20px,2.6vmin,30px);line-height:1;
  color:var(--gold-soft);background:rgba(20,19,16,.9);
  border:1px solid var(--line);border-radius:50%;
  cursor:pointer;transition:color .15s ease,border-color .15s ease;
  /* Grow the tappable area past the visible circle without moving anything. */
  touch-action:manipulation;
}
.tmq-lb-close::after,.tmq-lb-nav::after{content:"";position:absolute;inset:-6px}
.tmq-lb-close:hover,.tmq-lb-nav:hover{color:var(--gold);border-color:var(--gold)}
.tmq-lb-close{top:14px;right:16px}
.tmq-lb-prev{left:clamp(6px,1.6vw,22px);top:50%;transform:translateY(-50%)}
.tmq-lb-next{right:clamp(6px,1.6vw,22px);top:50%;transform:translateY(-50%)}
.tmq-lb.is-single .tmq-lb-nav{display:none}
.tmq-lb-close:focus-visible,.tmq-lb-nav:focus-visible{outline:2px solid var(--gold);outline-offset:2px}

.tmq-lb-cap{
  grid-row:2;margin:12px 0 0;
  font-size:14px;color:var(--text);text-align:center;max-width:30em;
}
.tmq-lb-cap:empty{display:none}
.tmq-lb-count{
  grid-row:3;margin:6px 0 0;
  font-size:12px;letter-spacing:1px;color:var(--muted);
}
.tmq-lb-count:empty{display:none}
.tmq-lb-hint{
  grid-row:4;margin:10px 0 0;
  font-size:11.5px;color:rgba(255,255,255,.34);text-align:center;
}
@media(max-width:700px){
  .tmq-lb-hint{display:none}
  .tmq-lb-prev{left:4px}
  .tmq-lb-next{right:4px}
}

/* ================================================================
   BLOG  (/blog/)
   The subject is one stone, so the writing is organised by question:
   the topics lead, because that is how a buyer arrives. Card measure
   is 600px, matching tmq-card, and the article column is narrower
   still - these are read, not glanced at.
   ================================================================ */
.kb-topics{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(238px,1fr));
  gap:12px;margin:26px 0 34px;
}
.kb-topic{
  display:block;text-decoration:none;color:inherit;
  background:var(--panel,#141310);border:1px solid var(--line);
  border-radius:12px;padding:18px 18px 16px;
  transition:border-color .16s ease,transform .16s ease;
}
.kb-topic:hover{border-color:rgba(201,168,106,.42);transform:translateY(-2px)}
.kb-topic-n{
  display:inline-block;font-size:11px;letter-spacing:1px;font-weight:700;
  color:var(--gold-soft);margin-bottom:9px;
}
.kb-topic-t{display:block;font-size:16px;font-weight:600;color:var(--text);margin-bottom:6px;line-height:1.3}
.kb-topic-d{display:block;font-size:12.5px;line-height:1.55;color:var(--muted)}

/* the lead article, given more room because it is the newest thing */
.kb-lead{margin:0 0 30px}
.kb-lead-card{
  display:grid;grid-template-columns:1.15fr 1fr;gap:0;
  text-decoration:none;color:inherit;
  background:var(--panel,#141310);border:1px solid var(--line);
  border-radius:14px;overflow:hidden;
  transition:border-color .16s ease;
}
.kb-lead-card:hover{border-color:rgba(201,168,106,.42)}
.kb-lead-img{display:block;background:var(--panel-2)}
.kb-lead-img img{width:100%;height:100%;max-height:340px;object-fit:cover;display:block}
.kb-lead-img.is-blank{display:flex;align-items:center;justify-content:center;min-height:220px}
/* No cover picture, so the card becomes one column rather than half empty.
   The class on the card itself is the primary hook; :has() is only a safety
   net for a markup variant, because older Safari ignores it silently and a
   half-empty lead card is worse than a plain one. */
.kb-lead-card.is-nocover{grid-template-columns:1fr}
@supports selector(:has(*)){
  .kb-lead-card:has(.kb-lead-img.is-blank){grid-template-columns:1fr}
}
.kb-lead-body{padding:26px 28px;display:flex;flex-direction:column;justify-content:center}
.kb-lead-tag{
  font-size:10px;letter-spacing:1px;text-transform:uppercase;
  color:var(--gold-soft);margin-bottom:10px;
}
.kb-lead-body h2{font-size:23px;line-height:1.28;margin:0 0 10px;color:var(--text)}
.kb-lead-body p{font-size:14px;line-height:1.6;color:var(--muted);margin:0 0 16px}
.kb-more{font-size:13px;color:var(--gold-soft);font-weight:600}

/* card grid */
.kb-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(258px,1fr));gap:16px}
.kb-card{
  display:flex;flex-direction:column;text-decoration:none;color:inherit;
  background:var(--panel,#141310);border:1px solid var(--line);
  border-radius:12px;overflow:hidden;
  transition:border-color .16s ease,transform .16s ease;
}
.kb-card:hover{border-color:rgba(201,168,106,.42);transform:translateY(-2px)}
.kb-card-img{display:block;background:var(--panel-2);aspect-ratio:4/3;overflow:hidden}
.kb-card-img img{width:100%;height:100%;object-fit:cover;display:block}
.kb-card-img.is-blank{display:flex;align-items:center;justify-content:center}
.kb-card-fb{font-size:22px;letter-spacing:2px;color:var(--muted);opacity:.42;font-weight:600}
.kb-card-body{padding:15px 16px 17px;display:flex;flex-direction:column;flex:1}
.kb-card-tag{
  font-size:10px;letter-spacing:.7px;text-transform:uppercase;
  color:var(--gold-soft);margin-bottom:7px;
}
.kb-card-body h3{font-size:15.5px;line-height:1.4;margin:0 0 7px;color:var(--text);font-weight:600}
.kb-card-body p{font-size:13px;line-height:1.55;color:var(--muted);margin:0 0 11px;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.kb-card-m{font-size:11.5px;color:var(--muted);opacity:.72;margin-top:auto}
.kb-empty{color:var(--muted);padding:30px 0}

/* ---------- one article ---------- */
.kb-article{padding-top:26px}
/* ⛔ 760px was 80 characters a line. The measure is 31em. */
.kb-head{max-width:30em;margin:0 0 26px}
.kb-head h1{font-size:35px;line-height:1.2;margin:0 0 13px;letter-spacing:-.5px}
.kb-head .lede{font-size:16.5px;line-height:1.65;color:var(--muted);margin:0 0 14px}
.kb-meta{font-size:12.5px;color:var(--muted);margin:0;display:flex;gap:9px;align-items:center;flex-wrap:wrap}

/* Credit line for a shared article. Deliberately above the body: a reader who
   would want to know who wrote it should not have to finish first. */
.kb-credit{font-size:13px;color:var(--muted);margin:14px 0 0;padding:10px 14px;
  border-left:3px solid var(--gold);background:rgba(201,168,106,.07);line-height:1.6}
.kb-credit-tag{display:inline-block;font-size:10px;letter-spacing:.6px;text-transform:uppercase;
  padding:2px 8px;border-radius:3px;background:rgba(201,168,106,.16);color:var(--gold);
  border:1px solid rgba(201,168,106,.42);margin-right:8px;font-weight:600;vertical-align:1px}
.kb-credit a{color:var(--gold)}

/* Sourced-fact list. Each row quotes somebody else's published figure and
   links back, so it is set apart from our own prose on purpose: a reader must
   be able to see at a glance which numbers are borrowed and which are ours. */
.kb-factlist{list-style:none;margin:18px 0 26px;padding:0}
.kb-factlist li{border-left:3px solid rgba(201,168,106,.55);background:rgba(201,168,106,.05);
  padding:12px 16px;margin:0 0 10px;font-size:14.5px;line-height:1.7}
.kb-factlist cite{font-style:normal;color:var(--gold);font-size:13px;font-weight:600}
.kb-factlist a{color:var(--gold);font-size:12.5px;white-space:nowrap;margin-left:4px}

/* Where to go next. Internal links move weight through our own site, which is
   the point of publishing these articles rather than leaving them standalone. */
.kb-nextlinks{list-style:none;margin:14px 0 24px;padding:0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px}
.kb-nextlinks li{margin:0}
.kb-nextlinks a{display:block;padding:11px 15px;border:1px solid var(--line);border-radius:4px;
  text-decoration:none;font-size:14px;color:var(--trz-ink-2);background:var(--panel,#141310)}
.kb-nextlinks a:hover{border-color:var(--gold);color:var(--gold)}

/* An in-article photograph of our own stock. It is what makes the piece read
   as ours rather than as a citation: the words may come from the trade, the
   picture is the material we actually ship. */
.kb-figure{margin:26px 0}
.kb-figure-img{display:block;width:100%;height:auto;border-radius:4px;border:1px solid var(--line)}
.kb-figure figcaption{margin-top:9px;font-size:12.5px;line-height:1.6;color:var(--muted)}

/* The questions this article answers. Visible on the page as well as in the
   schema: a reader (and a model verifying a source) can only trust a claim
   they can actually see. */
.kb-faq{margin:32px 0 8px;padding-top:26px;border-top:1px solid var(--line)}
.kb-faq h2{font-size:20px;margin:0 0 18px}
.kb-faq-item{margin:0 0 18px}
/* ⛔ THREE COLOURS IN THE KNOWLEDGE-BASE BLOCK WERE NAMED INSTEAD OF
   REFERENCED, AND THE BLOG POSTS WEAR THIS BLOCK.

   `.kb-faq-item` is the FAQ card, and the body of every one of the
   seventy-one blog posts is rendered inside it. So the three rules that
   named a colour rather than a variable were painting the whole blog:

       .kb-faq-item p        #c6c1b4  ->  1.72:1   the article's own text
       .kb-faq-item h3       #efe9dc  ->  1.16:1   the heading
       .kb-nextlinks a       #d6d1c4  ->  1.46:1   the "more like this" links

   ⛔ A VARIABLE CANNOT FIX A LITERAL -- the same lesson as the dark CTA
   band. The other forty rules in this block name a variable, and the
   variable was re-pointed for this paper station, so they are all correct.
   These three were the exceptions, and they were the ones a reader sees
   most of, because they are the body of the article.

   The values they are given are the station's own: --trz-ink-2 for prose
   and --trz-ink for the heading, both measured against the paper ground
   (11.51:1 and 17.74:1). */
.kb-faq-item h3{font-size:15.5px;line-height:1.5;margin:0 0 6px;color:var(--trz-ink)}
.kb-faq-item p{margin:0;font-size:14.5px;line-height:1.7;color:var(--trz-ink-2)}
.kb-dot{opacity:.5}

.kb-hero{margin:0 0 30px}
.kb-hero img{width:100%;max-height:560px;object-fit:cover;border-radius:14px;display:block;border:1px solid var(--line)}
.kb-hero figcaption{font-size:12px;color:var(--muted);margin-top:8px;text-align:center}

/* The reading column. 680px is roughly 70 characters at this size, which is
   where long-form technical text stops being tiring. */
.kb-body{max-width:30em;margin:0;font-size:15.5px;line-height:1.78;color:var(--text-soft)}
.kb-body p{margin:0 0 1.15em}
.kb-body h2{font-size:23px;line-height:1.32;margin:1.9em 0 .7em;color:var(--text);letter-spacing:-.2px}
.kb-body h3{font-size:18.5px;line-height:1.36;margin:1.6em 0 .6em;color:var(--text)}
.kb-body h4{font-size:16px;line-height:1.4;margin:1.4em 0 .5em;color:var(--text)}
.kb-body ul,.kb-body ol{margin:0 0 1.2em;padding-left:1.35em}
.kb-body li{margin-bottom:.45em}
.kb-body img{border-radius:10px;margin:1.2em 0}
.kb-body figure{margin:1.4em 0}
.kb-body figcaption{font-size:12.5px;color:var(--muted);margin-top:8px;text-align:center}
.kb-body blockquote{
  margin:1.5em 0;padding:14px 18px;border-left:3px solid var(--gold);
  background:var(--panel,#141310);color:var(--text-soft);font-size:15px;
}
.kb-body a{color:var(--gold-soft)}
.kb-body table{width:100%;border-collapse:collapse;margin:1.4em 0;font-size:14px}
.kb-body th,.kb-body td{padding:10px 12px;border:1px solid var(--line);text-align:left;vertical-align:top}
.kb-body th{background:var(--panel,#141310);color:var(--text);font-weight:600}
.kb-body code{background:var(--panel-2);padding:2px 6px;border-radius:3px;font-size:.9em}

/* A stated source. A figure on this site that cannot be traced is worth
   nothing to somebody who has to sign the material off. */
.kb-source{
  margin:2em 0 0;padding:13px 16px;border-left:3px solid rgba(201,168,106,.5);
  background:var(--panel,#141310);font-size:13px;line-height:1.6;color:var(--muted);
}
.kb-source strong{color:var(--gold-soft);margin-right:6px;letter-spacing:.4px;font-size:11px;text-transform:uppercase}
.kb-foot-topic{margin:1.6em 0 0;font-size:13px;color:var(--muted)}
.kb-foot-topic a{color:var(--gold-soft)}

.kb-more-wrap{margin:52px 0 0;padding-top:28px;border-top:1px solid var(--line)}
.kb-more-wrap h2{font-size:21px;margin:0 0 20px;color:var(--text)}
.kb-grid.is-small{grid-template-columns:repeat(auto-fill,minmax(224px,1fr));gap:14px}

@media(max-width:820px){
  .kb-lead-card{grid-template-columns:1fr}
  .kb-lead-img img{max-height:220px}
  .kb-head h1{font-size:28px}
  .kb-head .lede{font-size:15.5px}
  .kb-body{font-size:15px}
}

/* ---------- per-stone knowledge block ----------
   The homepage block that cannot be written for any other stone. Styling only
   distinguishes it from the other cards; what makes it valuable is the copy
   behind it, and that copy is per stone (config/page-copy-<slug>.php).

   Left border in the stone's own accent is deliberate: the block reads as
   "this material", not as "another section", which is the visual cue a buyer
   comparing two of our sites picks up without reading it. */
.stone-knowledge{background:var(--panel);border-top:1px solid var(--line)}
.stone-knowledge .section-head{margin-bottom:22px}
.stone-knowledge .grid{gap:16px}
.sk-card{
  border:1px solid var(--line);
  border-left:3px solid var(--gold);
  background:var(--ink-2);
  border-radius:var(--radius);
  overflow:hidden;
}
.sk-card .body{padding:20px 20px 22px}
.sk-card .kicker{
  color:var(--gold);font-size:11.5px;font-weight:700;letter-spacing:1.6px;
  text-transform:uppercase;margin:0 0 8px;
}
.sk-card h3{font-size:17.5px;line-height:1.35;margin:0 0 10px;color:var(--text)}
.sk-card p{margin:0;color:var(--text-soft);font-size:14.5px;line-height:1.72}
@media (max-width:820px){
  .sk-card{padding:0}
}

/* ---------- group photograph ----------
   Rendered only for stones whose config names an image for a form group, so a
   stone with no photographs gets no element and no caption. The photo is the
   first thing a buyer looks at on a stone site, and a page of headings with no
   picture on it reads as a site that has nothing to show. */
.fg-photo{display:block;overflow:hidden;border-radius:var(--radius);margin-bottom:14px;line-height:0}
.fg-photo img{width:100%;height:210px;object-fit:cover;display:block;transition:transform .5s ease}
.fg:hover .fg-photo img{transform:scale(1.03)}

.group-hero{margin:0 0 26px;overflow:hidden;border-radius:var(--radius);line-height:0}
.group-hero img{width:100%;height:380px;object-fit:cover;display:block}

@media (max-width:820px){
  .fg-photo img{height:160px}
  .group-hero img{height:220px}
}

/* ==========================================================================
   TERRAZZO — its own visual system
   ==========================================================================
   NOT THE LUXURY STONE LOOK, AND THAT IS THE POINT.
   ---------------------------------------------------------
   The other three sites on this network are dark ground, gold rule, rice text.
   That reads as "this stone is precious". Terrazzo is not precious. It is a
   process: aggregate in a binder, ground flat, specified by millimetre. Fifty
   domains wearing the same luxury skin is fifty domains a search engine has
   learned to discount, and this one is the only site on the network whose
   subject does not want that skin.

   So the visual argument is a MATERIAL SAMPLE BOOK next to an ENGINEERING
   SECTION DRAWING:

     - paper, not velvet. A warm off-white with a hint of the binder in it.
     - ink, not gold. Near-black, and every figure is set in it.
     - ONE red, used only where a figure or a limit appears. It is the colour
       of a dimension line on a drawing, and it appears nowhere decorative.
     - monospace for figures ONLY. Never for prose. A number you can check is
       a number in a typeface that aligns; a number in a serif is a number
       somebody chose.

   THE AGGREGATE IS THE ORNAMENT.
   The three other sites use stone texture as decoration. Here the decoration
   IS the subject: small discrete chips in a continuous matrix. It appears as
   the section-drawing fills, as the chip marks in the rule, and as nothing
   else. No marble veining, no wave texture, no gold dust. Those belong to
   other materials.

   ⛔ NO TEXTURE BACKGROUNDS, NO NOISE, NO GRADIENTS.
   A specification page is read under a lamp, often on a tablet, often printed.
   Anything behind the text that is not information reduces contrast and
   fights the figures. The pages below are flat on purpose.
   ========================================================================== */

:root{
  /* Binder. A warm off-white, closer to cement than to paper stock. */
  --trz-paper:      #FBFAF7;
  --trz-paper-2:    #F4F2ED;
  --trz-paper-3:    #ECEAE3;

  /* Ink. Near-black rather than pure black; a drawing is never drawn in
     absolute black and pure black on off-white vibrates. */
  --trz-ink:        #16130F;
  --trz-ink-2:      #3A362F;
  --trz-ink-3:      #5F5E5A;
  --trz-ink-4:      #8A8578;

  /* The dimension line. Used for figures, for limits, and for nothing else. */
  /* ⛔ THE CRIMSON WAS 0.04 SHORT OF THE FLOOR AS TEXT.
     var(--trz-red) measured 4.46:1 on the paper ground against a 4.5 floor, and
     twelve rules named the colour outright instead of naming this
     variable -- so changing the variable would not have moved them.
     #B93F2B measures 5.28:1 as text and 5.51:1 with white text on it,
     which is what the hover rules need. */
  --trz-red:        #B93F2B;
  --trz-red-soft:   rgba(193,68,46,.10);

  /* Rules. A drawing is mostly hairline. */
  --trz-rule:       #D8D4CA;
  --trz-rule-2:     #B8B3A6;

  /* Aggregate. The five chip tones of a neutral terrazzo. */
  --trz-chip-1:#16130F; --trz-chip-2:#5F5E5A; --trz-chip-3:#8A8578;
  --trz-chip-4:#B4AFA2; --trz-chip-5:#E4E0D6;
}

/* ---------- the page itself ---------- */
body.trz{
  background:var(--trz-paper);
  color:var(--trz-ink);
  font-family:"Helvetica Neue",Helvetica,-apple-system,BlinkMacSystemFont,"Segoe UI",Arial,sans-serif;
  letter-spacing:.005em;
}

/* ============================================================================
   THE INHERITED PALETTE, RE-DECLARED FOR THIS SITE
   ============================================================================
   BOSS, 2026-10-19: "文字看起来很累. 第三站可以白底黑字或者类似 Apple 网站的
   显示风格就行."

   ⛔ WHAT WAS ACTUALLY WRONG, MEASURED IN A BROWSER
   Not a preference. The page background was ALREADY off-white (#FBFAF7) and
   the H1 and body text were ALREADY near-black (#16130F) — and the body
   paragraphs were still #D8CFC0, a rice-white left over from the dark sites.

   Measured contrast against the page background:

       body / h1 / h2        17.74:1   fine
       body paragraph          1.48:1   <-- illegible
       list item               1.48:1   <-- illegible
       caption / small note    1.42:1   <-- illegible

   ⛔ 1.48:1 IS NOT A DARK THEME. It is dark-theme text on a light ground, and
   WCAG puts the floor for body text at 4.5:1. The third site measures 11.56:1
   on the same paragraph because it is dark on dark.

   ⛔ WHY IT LOOKED LIKE A STYLE CHOICE AND NOT A BUG
   `body.trz` sets `background` and `color`, which is enough for a page whose
   text inherits. But this stylesheet has 44 rules using --text-soft and 67
   using --muted, and every one of them names the variable explicitly. Setting
   the colour on body does not reach a child that already decided what colour it
   is, so the paragraphs stayed rice-white on paper and the page rendered
   exactly as it was written: no error, no warning, HTTP 200.

   ⛔ WHY THE FIX IS HERE AND NOT IN FORTY PLACES
   Because the fault is in the VARIABLES, not in forty selectors. Re-pointing
   --text / --text-soft / --muted / --panel / --line / --ink inside body.trz
   changes every rule that reads them, in one place, with no chance of missing
   one — and leaves the dark sites' own values untouched, because this file is
   this site's copy of the stylesheet and the block is scoped to a class this
   site's body carries alone.

   ⛔ THE VALUES ARE CHOSEN AGAINST THE PAPER, NOT AGAINST THE OLD DARK GROUND.
       --text  #16130F  17.74:1  headings and links
       --text-soft #3A362F  11.51:1  body prose — the colour BOSS is asking for
       --muted   #5F5E5A  6.02:1  notes, still above the 4.5 floor
   ========================================================================== */
body.trz{
  /* The three that were still rice-on-paper. */
  --text:      #16130F;
  --text-soft: #3A362F;
  --muted:     #5F5E5A;

  /* Surfaces: the dark panels become paper tints, so a card is still a card
     and still separates from the page without a heavy fill. */
  --ink:    #16130F;
  --ink-2:  #ECEAE3;
  --panel:  #F4F2ED;
  --panel-2:#FFFFFF;
  --line:   #D8D4CA;

  /* The shadow was sized for a dark ground (0.45 alpha on near-black reads as
     a hard edge). On paper it has to be a fifth of that or the page looks
     stained. */
  --shadow: 0 2px 10px rgba(22,19,15,.06);

  /* Gold is the one colour that does NOT survive a light ground unchanged:
     #C9A86A on #FBFAF7 measures 2.1:1. Links are the most-clicked text on the
     site, so they take the ink colour and gold is kept for rules and marks
     where contrast against paper is not the question. */
  --gold-soft:#8A6D1F;
  --gold:     #6F561A;
}

/* ⛔ AND THE TWO PLACES THAT SET A COLOUR BY HAND, NOT BY VARIABLE.
   `--gold-soft` cannot fix these, and both of them are text a reader clicks. */
body.trz a{color:var(--gold-soft)}
body.trz a:hover{color:var(--gold)}

/* ⛔ THE DARK CTA BAND, AND THE TEXT THAT VANISHED INSIDE IT.
 *
 * `.cta-band` is a dark panel — a deep blue-black gradient — and on the three
 * dark stations that is what it was designed for, where the site's own text
 * colour is light rice on dark ground and the heading reads.
 *
 * On this station the body block above resets `--text` to ink and
 * `--text-soft` to the paper-side grey, because this site is a paper
 * station. The CTA band was never given the same treatment, so its heading
 * inherited the ink colour and its paragraph inherited the paper-side grey,
 * and both of them were painted onto the dark panel:
 *
 *     H2  #16130F on #1a2230 -> about 1.1:1, invisible
 *     p   #3A362F on #11161d -> about 1.4:1, invisible
 *
 * A reader sees a dark box with a gold button and no words in it. The
 * contrast gate did not catch it, and the reason is worth recording: the
 * gate compared each element's text colour with the PAGE background rather
 * than with the panel it sits in, so dark text on a dark panel computed as
 * high contrast against the paper. The panel's own text colour is stated
 * here, explicitly, because "inherited from a variable that was reset for
 * the ground" is exactly the way this went wrong.
 *
 * The panel stays dark. A dark band on a paper page is a deliberate
 * contrast, and the button inside it was built for it. */
body.trz .cta-band h2{color:#F2ECE1}
body.trz .cta-band p{color:#D8CFC0}
body.trz .btn-ghost{border-color:var(--line);color:var(--text-soft)}
body.trz .btn-ghost:hover{color:var(--text)}

/* ⛔ SMALL PRINT WAS THE WORST OF IT.
   Captions and notes measured 1.42:1 at 11.5px, which is the combination that
   makes a page feel tiring fastest: small AND faint. Two changes, not one. */
body.trz .chip,
body.trz .kicker,
body.trz .trz-fig,
body.trz .eyebrow,
body.trz .sub{color:var(--muted)}

/* ============================================================================
   THE PARTS THAT NAMED A DARK COLOUR INSTEAD OF A VARIABLE
   ============================================================================
   ⛔ A VARIABLE CANNOT FIX A LITERAL. These rules write the dark site's values
   into the declaration rather than naming a variable, so re-pointing the
   variables left them exactly where they were and the page came out half
   light: dark sticky bar, dark buttons, dark input wells on a paper page.

   ⛔ WHY THE BAR WAS LEFT DARK RATHER THAN UNDONE ON PURPOSE
   A dark bar over a paper page is not automatically wrong — plenty of sites
   do it — but BOSS asked for the third station's register, and that station
   is dark all the way down. Half-and-half reads as a mistake even when both
   halves are individually defensible, so the bar goes light with the page and
   keeps a hairline so it still separates while sticking.
   ========================================================================== */
body.trz .topbar{
  background:rgba(251,250,247,.92);
  border-bottom:1px solid var(--trz-rule);
}
/* ⛔ THE GOLD MARK KEPT ITS FILL BUT NOT ITS TEXT.
   .brand .mark paints a gold gradient and the letter inside it is the old
   rice-white, which on gold is unreadable now that --gold is a darker value. */
body.trz .brand .mark{color:#FBFAF7}
body.trz .btn{
  background:var(--gold);
  border-color:var(--gold);
  /* ⛔ A GOLD BUTTON WITH GOLD TEXT IS A BUTTON WITH NO LABEL.
     Measured 1.03:1 this morning on the third station and 17.5:1 here only
     because the dark sites' gold was light enough to read its own text. */
  color:#FBFAF7;
}
body.trz .btn:hover{background:var(--gold-deep);border-color:var(--gold-deep);color:#FBFAF7}
body.trz .btn-ghost{background:transparent;border-color:var(--trz-rule-2);color:var(--text-soft)}
body.trz .btn-ghost:hover{background:var(--trz-paper-2);color:var(--text)}

/* ⛔ THE DOWNLOAD BUTTON WAS NOT IN THAT LIST, AND IT IS A GOLD BUTTON.
 *
 * `.dl-go` is the button on every document card in /download/. It paints a
 * gold gradient and, in the dark stations, a dark label on that gold. The
 * light-theme block above covers `.btn` and `.brand .mark` but not `.dl-go`,
 * so the label fell through to `body.trz a` -- the rule that gives links
 * their gold-soft colour -- and ended up gold on gold:
 *
 *     label  #8A6D1F on a gold gradient  ->  1.40:1
 *
 * A download button whose label cannot be read. The fix is the same one the
 * `.btn` rule above already uses: a solid gold ground with the rice-white
 * label, which measures 7:1. The gradient is dropped for this station
 * because --gold is a dark olive here, and a label that reads on one end of
 * a gradient does not read on the other.
 *
 * The locked and "soon" variants keep their own colours: they are text on
 * paper, and a gold outline with a gold label is 4.7:1 there. */
body.trz .dl-go{background:var(--gold);color:#FBFAF7}
body.trz .dl-go:hover{background:var(--gold-deep);color:#FBFAF7}
body.trz .dl-go.is-lock{background:transparent;color:var(--gold-soft)}
body.trz .dl-go.is-soon{background:transparent;color:var(--muted)}

/* ⛔ THE NAVIGATION PILL, AND THE GOLD THAT WAS A LITTLE TOO LIGHT.
 *
 * The "Post Your Needs" pill in the header is a 10% gold tint on paper, and
 * the label on it was --gold-soft, which measured 4.35:1 against that tint:
 * just under the 4.5 floor for text this size. The fix is one value.
 * #7E6118 measures 5.17:1 on the pill and 5.57:1 on the paper, so the
 * same colour is used for the label, the pill and every other gold-soft
 * mark on the page -- and every one of them gets more readable. */
body.trz{--gold-soft:#7E6118}

/* ⛔ INPUT WELLS ON PAPER ARE WHITE, NOT INK.
   A filled dark input on a paper page reads as a hole in the page, and the
   placeholder inside it was the same rice-white that made the prose tiring. */
body.trz .field input,
body.trz .field textarea,
body.trz .field select{
  background:#FFFFFF;
  border-color:var(--trz-rule);
  color:var(--trz-ink);
}
body.trz .field input::placeholder,
body.trz .field textarea::placeholder{color:var(--muted);opacity:1}
body.trz .field input:focus,
body.trz .field textarea:focus,
body.trz .field select:focus{
  border-color:var(--gold);
  box-shadow:0 0 0 3px rgba(143,110,32,.12);
}

/* ⛔ THE CARDS AND THE CALLOUTS ARE TINTS OF PAPER, NOT DARK PANELS.
   --panel was re-pointed above, and these read it, so they follow.
   ⛔ EVERY SELECTOR BELOW WAS READ OFF A LIVE PAGE, NOT REMEMBERED.
   The first draft of this block named answer-figcaption, answer-table-cap,
   acct-badges and spec-block — four class names that do not exist on this site
   and matched nothing. They were harmless (a rule that matches nothing does
   nothing) and they were worthless, and the reason they were written from
   memory is the same reason seven form slugs were written from memory three
   times this week. */
body.trz .card{background:#FFFFFF;border-color:var(--trz-rule)}
body.trz .card h3{color:var(--trz-ink)}
body.trz .card .chip{color:var(--muted)}
body.trz .pager a,
body.trz .pager span{background:#FFFFFF;border-color:var(--trz-rule);color:var(--text-soft)}
body.trz .pager .current{background:var(--trz-ink);border-color:var(--trz-ink);color:#FBFAF7}
body.trz .btn--ghost,
body.trz .btn.btn--ghost{background:transparent;border-color:var(--trz-rule-2);color:var(--text-soft)}

/* ⛔ FOOTER: A HAIRLINE AND A PAPER TINT, NOT A BLACK BLOCK.
   The footer was the last thing on every page still painted near-black, and a
   black footer under a paper page is the single most obvious sign that two
   design languages were mixed. The class on the live pages is `.site` on the
   footer element itself. */
body.trz .site{background:var(--trz-paper-2);border-top:1px solid var(--trz-rule)}
body.trz .site h4{color:var(--trz-ink)}
body.trz .site a{color:var(--text-soft)}
body.trz .site a:hover{color:var(--gold-soft)}
body.trz .disclaimer{color:var(--muted);border-top:1px solid var(--trz-rule)}

/* ⛔ THE ANSWER PAGE'S OWN BLOCKS. These names came off the live answer page:
   answer-table, answer-figure, answer-direct, answer-sources, answer-cta. */
body.trz .answer-table th{color:var(--trz-ink);border-bottom-color:var(--trz-rule-2)}
body.trz .answer-table td{color:var(--trz-ink-2);border-bottom-color:var(--trz-rule)}
body.trz .answer-figure{background:#FFFFFF;border-color:var(--trz-rule)}
body.trz .answer-figure figcaption{color:var(--muted)}
body.trz .answer-sources{background:var(--trz-paper-2);border-color:var(--trz-rule)}
body.trz .answer-sources-lede,
body.trz .answer-boundary{color:var(--muted)}

/* ⛔ FIGURES SET IN MONOSPACE, AND ONLY FIGURES.
   Every .trz-fig element is a number or a unit or a code. Prose never gets
   this treatment, because a page set entirely in monospace reads as a
   terminal and a page set in two typefaces reads as a design decision. */
.trz-fig,.trz-unit,.answer-table td,.answer-table th.answer-num,
code,.kbd,.metric-num{
  font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  font-variant-numeric:tabular-nums;
}

/* ---------- the chip rule ----------
   The one decorative mark on the site. A hairline interrupted by aggregate,
   used to separate a section from the one before it. It is the site's totem:
   terrazzo is discrete chips in a continuous field, and so is this rule. */
.trz-chiprule{
  position:relative;
  height:14px;
  margin:2.6rem 0 1.6rem;
  border:0;
  height:2px;
  background:var(--trz-rule);
}
.trz-chiprule::before,
.trz-chiprule::after{
  content:"";
  position:absolute;
  top:50%;
  transform:translateY(-50%);
  border-radius:50%;
}
.trz-chiprule::before{
  right:0; width:7px; height:7px; background:var(--trz-chip-1);
}
.trz-chiprule::after{
  right:14px; width:5px; height:5px; background:var(--trz-red);
}

/* ---------- answer page ---------- */
.answer{max-width:780px;margin:0 auto;padding:2.2rem 1.25rem 4rem}

.answer-crumb{
  font-size:.78rem;letter-spacing:.09em;text-transform:uppercase;
  color:var(--trz-ink-4);margin:0 0 1.1rem;
}
.answer-crumb a{color:var(--trz-ink-3);text-decoration:none;border-bottom:1px solid var(--trz-rule-2)}
.answer-crumb a:hover{color:var(--trz-ink);border-bottom-color:var(--trz-ink)}
.answer-crumb .sep{color:var(--trz-chip-4);margin:0 .35em}

/* ⛔ THE H1 IS A QUESTION, SO IT IS SET LIKE ONE.
   Not 48px. The old site's H1 was a product name and wanted to be enormous.
   This H1 is a sentence somebody typed, and it competes with the answer below
   it for the same attention. Set large enough to be the question, small enough
   that the answer still arrives quickly. */
.answer h1{
  font-size:1.95rem;line-height:1.24;font-weight:500;
  letter-spacing:-.014em;color:var(--trz-ink);margin:0 0 1.6rem;
  max-width:22ch;
}

/* THE ANSWER BLOCK. The most-quoted object on the site, so it is the only
   place on a page with a tinted ground, and it carries the left rule. */
.answer-direct{
  background:var(--trz-paper-2);
  border-left:3px solid var(--trz-ink);
  padding:1.25rem 1.4rem;
  font-size:1.08rem;line-height:1.62;color:var(--trz-ink);
  margin:0 0 2.2rem;
}
.answer-direct strong{font-weight:600}
.answer-direct--empty{
  border-left-color:var(--trz-red);
  background:var(--trz-red-soft);
  font-size:.98rem;
}

/* ---------- the drawing ---------- */
.answer-figure{margin:0 0 2.4rem;padding:0}
.answer-figure svg{
  display:block;width:100%;height:auto;
  background:var(--trz-paper);
  border:1px solid var(--trz-rule);
  border-radius:2px;
}

/* ⛔ A FIGURE IS NOT SCALED DOWN UNTIL ITS LABELS DISAPPEAR.
   `svg{width:100%}` on a 680-unit-wide drawing inside a 560px column scales
   the whole thing to 82%, and a 10px figure caption comes out under 9px while
   the axis labels crowd their own tick marks. Squeezing a drawing until it
   fits is how a chart ends up technically responsive and practically
   unreadable.
 *
 * ⛔ SO THE FLOOR IS SET AND THE BOX SCROLLS, WHICH IS THE OPPOSITE OF
 * `overflow:hidden`. A hidden overflow on a figure does not make it fit; it
 * makes the right-hand edge of the drawing vanish, and the right edge is where
 * every value on these charts is printed. A horizontal scrollbar costs the
 * reader one gesture and shows them the whole figure.
 *
 * ⛔ AND NO SCROLLBAR ON A PHONE, BECAUSE ON A PHONE THE DRAWING IS WIDER THAN
 * THE SCREEN AND THERE IS NOTHING TO SCROLL TO. There the figure is scaled and
 * the reader is told in the caption that it is scaled, which is a sentence
 * about the drawing rather than a silent shrink. */
.answer-figure svg{min-width:620px}
.answer-figure{
  overflow-x:auto;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior-x:contain;
}
@media (max-width:640px){
  .answer-figure svg{min-width:0;width:100%}
  .answer-figure figcaption::after{
    content:" Shown smaller on a phone; the values are in the table below.";
    display:block;margin-top:.35rem;font-size:.72rem;opacity:.85;
  }
}
.answer-figure figcaption{
  margin-top:.6rem;
  font-size:.76rem;line-height:1.5;color:var(--trz-ink-4);
  letter-spacing:.02em;
}

/* ---------- the table ---------- */
.answer-table-block{margin:0 0 2.4rem}
.answer-h2{
  font-size:.8rem;font-weight:600;letter-spacing:.11em;text-transform:uppercase;
  color:var(--trz-ink-3);margin:0 0 .9rem;
}
.answer-table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.answer-table{
  width:100%;border-collapse:collapse;font-size:.88rem;
  background:var(--trz-paper);
}
.answer-table th,.answer-table td{
  padding:.62rem .8rem;text-align:left;
  border-bottom:1px solid var(--trz-rule);
  vertical-align:top;line-height:1.5;
}
.answer-table thead th{
  border-bottom:1.5px solid var(--trz-ink);
  font-size:.72rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--trz-ink);white-space:nowrap;
}
.answer-table tbody th{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:.8rem;font-weight:500;color:var(--trz-ink);white-space:nowrap;
}
/* ⛔ AN UNTESTED CELL LOOKS UNTESTED.
   It is set in the dimension-line red and in italic, with no background. A
   reader scanning for the figures must not be able to mistake a cell nobody
   filled in for a figure that was measured — on a specification sheet those
   two things mean opposite things. */
.answer-table td.is-untested{
  color:var(--trz-red);font-style:italic;
  font-family:system-ui,-apple-system,"Segoe UI",sans-serif;
}

/* ---------- why / boundary ---------- */
.answer-why,.answer-boundary{margin:0 0 2.4rem}
.answer-why p,.answer-boundary p{
  font-size:1rem;line-height:1.68;color:var(--trz-ink-2);margin:0 0 1rem;
}

/* THE BOUNDARY BLOCK. Tinted and ruled, because it is the page's claim to
   being different and it should not read as just another paragraph. */
.answer-boundary{
  background:var(--trz-paper-2);
  border:1px solid var(--trz-rule);
  border-top:2px solid var(--trz-red);
  padding:1.3rem 1.4rem;
}
.answer-boundary .answer-h2{color:var(--trz-red)}
.answer-boundary-link{margin:0;font-size:.88rem}
.answer-boundary-link a{color:var(--trz-ink);border-bottom:1px solid var(--trz-ink)}

/* ---------- related / supply / contact ---------- */
.answer-related{margin:0 0 2.4rem}
.answer-related ul{list-style:none;margin:0;padding:0;columns:2;column-gap:2rem}
.answer-related li{margin:0 0 .5rem;break-inside:avoid}
.answer-related a{
  color:var(--trz-ink);text-decoration:none;font-size:.92rem;
  border-bottom:1px solid var(--trz-rule-2);
}
.answer-related a:hover{border-bottom-color:var(--trz-ink)}

.answer-supply{
  border-top:2px solid var(--trz-ink);
  padding-top:1.4rem;margin:0 0 2.4rem;
}
.answer-supply p{font-size:.94rem;line-height:1.6;color:var(--trz-ink-2)}
.answer-supply-list{list-style:none;margin:0 0 1.2rem;padding:0;columns:2;column-gap:2rem}
.answer-supply-list li{margin:0 0 .45rem;break-inside:avoid;font-size:.92rem}
.answer-supply-list a{color:var(--trz-ink);text-decoration:none;border-bottom:1px solid var(--trz-rule-2)}
.answer-supply-none{
  background:var(--trz-paper-2);border-left:3px solid var(--trz-red);
  padding:.9rem 1.1rem;
}
.answer-cta{display:flex;gap:.7rem;flex-wrap:wrap;margin-top:1.2rem}

/* ⛔ 44px MINIMUM ON EVERY CONTROL.
   Measured, not assumed: the close button on this network was once 38×38 and
   nobody could hit it on a phone. */
.answer .btn,.answer-cta .btn{
  display:inline-flex;align-items:center;min-height:44px;
  padding:0 1.25rem;
  background:var(--trz-ink);color:var(--trz-paper);
  border:1px solid var(--trz-ink);border-radius:2px;
  font-size:.88rem;letter-spacing:.03em;text-decoration:none;cursor:pointer;
  transition:background .15s ease,color .15s ease;
}
.answer .btn:hover{background:var(--trz-red);border-color:var(--trz-red)}
.answer .btn--ghost{background:transparent;color:var(--trz-ink)}
.answer .btn--ghost:hover{background:var(--trz-ink);color:var(--trz-paper)}

.answer-notes{
  border-top:1px solid var(--trz-rule);padding-top:1.4rem;
  font-size:.94rem;line-height:1.65;color:var(--trz-ink-2);
}

@media (max-width:680px){
  .answer h1{font-size:1.6rem}
  .answer-related ul,.answer-supply-list{columns:1}
  .answer{padding:1.6rem 1rem 3rem}
}

/* ==========================================================================
   TERRAZZO — front page
   --------------------------------------------------------------------------
   No hero. The first screen is the question list, because that is what the
   data says the reader is holding when they arrive.
   ========================================================================== */
.trz-front{max-width:880px;margin:0 auto;padding:2.4rem 1.25rem 4rem}

.trz-masthead{
  display:flex;align-items:baseline;gap:.7rem;flex-wrap:wrap;
  margin:0 0 1.5rem;
}
.trz-masthead-name{
  font-size:1.35rem;font-weight:600;letter-spacing:-.02em;color:var(--trz-ink);
}
.trz-masthead-sub{
  font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--trz-ink-4);
  padding-left:.7rem;border-left:1px solid var(--trz-rule-2);
}

/* ⛔ THE FRONT H1 IS A SENTENCE ABOUT WHAT THE SITE ANSWERS.
   It is the largest type on the page and it is 27 words long, which is wrong
   for a marketing headline and right for this: it tells a visitor in one read
   whether their question is here. */
.trz-front-h1{
  font-size:1.9rem;line-height:1.28;font-weight:500;letter-spacing:-.016em;
  color:var(--trz-ink);margin:0 0 1.4rem;max-width:24ch;
}
.trz-front-lede{
  font-size:1.02rem;line-height:1.66;color:var(--trz-ink-2);
  margin:0 0 1.1rem;max-width:30em;
}
/* The honesty line. Small, red, and not a disclaimer — it is the reason the
   tables on this site are worth reading. */
.trz-front-honest{
  font-size:.9rem;line-height:1.6;color:var(--trz-ink-2);margin:0;max-width:30em;
}
.trz-front-honest em{color:var(--trz-red);font-style:normal;font-weight:600}

.trz-block-h{
  font-size:.78rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  color:var(--trz-ink-3);margin:0 0 1rem;
}

/* ---------- the question list: the first screen ---------- */
.trz-ask{margin:0 0 3rem}
.trz-ask-list{list-style:none;margin:0;padding:0;border-top:1px solid var(--trz-ink)}
.trz-ask-list li{border-bottom:1px solid var(--trz-rule)}
.trz-ask-list a{
  display:flex;align-items:baseline;gap:1rem;
  padding:1.05rem .3rem;
  text-decoration:none;color:var(--trz-ink);
  transition:background .14s ease,padding-left .14s ease;
}
.trz-ask-list a:hover{background:var(--trz-paper-2);padding-left:.9rem}
.trz-ask-n{
  font-size:.8rem;color:var(--trz-chip-4);
  min-width:1.6rem;flex-shrink:0;
}
.trz-ask-t{
  font-size:1.08rem;line-height:1.4;flex:1;
  letter-spacing:-.008em;
}
.trz-ask-go{color:var(--trz-ink-3);flex-shrink:0;font-size:1rem}
.trz-ask-list a:hover .trz-ask-go{color:var(--trz-red)}

/* ---------- kinds ---------- */
.trz-kinds{margin:0 0 3rem}
.trz-kind-grid{
  display:grid;gap:1px;
  grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  background:var(--trz-rule);
  border:1px solid var(--trz-rule);
}
.trz-kind{
  background:var(--trz-paper);
  padding:1.15rem 1.2rem;
  text-decoration:none;color:var(--trz-ink);
  display:flex;flex-direction:column;gap:.28rem;
  transition:background .14s ease;
}
.trz-kind:hover{background:var(--trz-paper-2)}
/* The count is set in monospace and in red. It is the reason the block exists
   and it is the only number in the navigation. */
.trz-kind-n{
  font-size:1.5rem;font-weight:500;color:var(--trz-red);
  line-height:1;letter-spacing:-.02em;
}
.trz-kind-name{
  font-size:.95rem;font-weight:600;letter-spacing:-.005em;
}
.trz-kind-blurb{
  font-size:.82rem;line-height:1.5;color:var(--trz-ink-3);
}

/* ---------- the big drawing ---------- */
.trz-section{margin:0 0 3rem}
.trz-section-lede{
  font-size:1rem;line-height:1.62;color:var(--trz-ink-2);
  margin:0 0 1.4rem;max-width:30em;
}
.trz-figure{margin:0 0 1.6rem}

/* ==========================================================================
   ⛔ THE FIGURES ARE NOT SCALED DOWN ON A PHONE. THEY SCROLL.
   --------------------------------------------------------------------------
   This is a fix for "I cannot see the site on my phone", reported 2026-10-16,
   and the cause was not a broken layout, a missing viewport or a failed asset.
   Every one of those was checked and was correct.

   The cause is one line: `width:100%` on an SVG whose viewBox is 768 units
   wide. On a 390 px phone the drawing is squeezed to 51% of its size, and a
   7 px axis label becomes 3.6 px. The picture is still there, it is still
   correct, and it is unreadable — which from the reader's side is the same as
   the site not working.

   ⛔ THE NAIVE FIX IS TO HIDE THE FIGURES ON MOBILE. That was rejected: the
   six-process comparison is the argument for why the rest of the site exists,
   and on a phone it is MORE needed, not less. Dropping it would make the site
   look right and remove the reason it was built.

   ⛔ SO BELOW 900px THE FIGURE KEEPS ITS SIZE AND THE CONTAINER SCROLLS.
   A figure you can swipe is a figure you can read. The scroll is only on the
   figure, so the page itself never scrolls sideways, and the caption stays put
   under it rather than travelling with it.

   ⛔ min-width:560px, NOT 320px. At 320 the six columns and their labels are
   already touching. 560 is the width at which the existing label sizes were
   drawn to be legible, so it is the width that preserves the drawing's own
   design rather than a number picked to stop an overflow. */
.trz-figure svg{
  display:block;width:100%;height:auto;
  background:var(--trz-paper);
  border:1px solid var(--trz-rule);border-radius:2px;
}
@media (max-width:900px){
  .trz-figure{
    overflow-x:auto;-webkit-overflow-scrolling:touch;
    /* ⛔ A scroll container with no visible edge reads as a clipped layout, so
       the fade is what tells the reader there is more of the drawing to the
       right. It is a gradient overlay, not a border, and it is not on the
       desktop layout where nothing is hidden. */
    -webkit-mask-image:linear-gradient(to right,#000 88%,transparent 100%);
    mask-image:linear-gradient(to right,#000 88%,transparent 100%);
  }
  .trz-figure svg{min-width:560px}
  /* ⛔ THE BORDER MOVES INSIDE THE SCROLLER, or it draws a box that is wider
     than the viewport and takes the whole page sideways with it. */
  .trz-figure svg{border:0}
  .trz-figure figcaption{position:relative;z-index:1}
}
.trz-figure figcaption{
  margin-top:.6rem;font-size:.76rem;line-height:1.5;color:var(--trz-ink-4);
}

/* ---------- the five processes ---------- */
.trz-process-list{
  list-style:none;margin:0;padding:0;
  display:grid;gap:1px;background:var(--trz-rule);
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  border:1px solid var(--trz-rule);
}
.trz-process-list a{
  background:var(--trz-paper);padding:1rem 1.1rem;
  text-decoration:none;color:var(--trz-ink);
  display:flex;flex-direction:column;gap:.3rem;
  transition:background .14s ease;
}
.trz-process-list a:hover{background:var(--trz-paper-2)}
.trz-p-name{font-size:.95rem;font-weight:600}
.trz-p-note{font-size:.82rem;line-height:1.5;color:var(--trz-ink-3)}
.trz-p-fig{font-size:.78rem;color:var(--trz-ink-2);margin-top:.15rem}
/* ⛔ "not tested" IS NEVER IN MONOSPACE-INK.
   A figure and an admission look identical if they share a style, and one of
   them is a lie by accident. The admission is set in the body's own face and
   in the red, in italic. */
.trz-p-fig--none{
  color:var(--trz-red);font-style:italic;
  font-family:system-ui,-apple-system,"Segoe UI",sans-serif;
}

/* ---------- the whole library ---------- */
.trz-library{margin:0 0 3rem}
.trz-lib-n{color:var(--trz-red);font-weight:600;margin-left:.3rem}
.trz-lib-list{
  list-style:none;margin:0;padding:0;
  columns:3;column-gap:2rem;
  border-top:1px solid var(--trz-rule);
}
.trz-lib-list li{
  margin:0;break-inside:avoid;
  border-bottom:1px solid var(--trz-rule);
}
.trz-lib-list a{
  display:block;padding:.55rem 0;
  font-size:.86rem;line-height:1.45;color:var(--trz-ink-2);
  text-decoration:none;
}
.trz-lib-list a:hover{color:var(--trz-ink);text-decoration:underline;text-underline-offset:3px}
.trz-empty{
  font-size:.92rem;line-height:1.6;color:var(--trz-ink-3);
  background:var(--trz-paper-2);border-left:3px solid var(--trz-rule-2);
  padding:1rem 1.2rem;margin:0;max-width:30em;
}

/* ---------- the commercial close ---------- */
.trz-supply{
  border-top:2px solid var(--trz-ink);
  padding-top:1.6rem;margin:0;
}
.trz-supply p{font-size:.98rem;line-height:1.65;color:var(--trz-ink-2);max-width:30em;margin:0 0 1.2rem}
.trz-supply-cta{display:flex;gap:.7rem;flex-wrap:wrap;margin:0}
.trz-supply .btn{
  display:inline-flex;align-items:center;min-height:44px;
  padding:0 1.25rem;background:var(--trz-ink);color:var(--trz-paper);
  border:1px solid var(--trz-ink);border-radius:2px;
  font-size:.88rem;letter-spacing:.03em;text-decoration:none;
  transition:background .15s ease,color .15s ease,border-color .15s ease;
}
.trz-supply .btn:hover{background:var(--trz-red);border-color:var(--trz-red);color:#fff}
.trz-supply .btn--ghost{background:transparent;color:var(--trz-ink)}
.trz-supply .btn--ghost:hover{background:var(--trz-ink);color:var(--trz-paper);border-color:var(--trz-ink)}

@media (max-width:820px){
  .trz-lib-list{columns:2}
}
@media (max-width:560px){
  .trz-lib-list{columns:1}
  .trz-front-h1{font-size:1.5rem}
  .trz-ask-list a{padding:.9rem .2rem;gap:.7rem}
  .trz-ask-t{font-size:1rem}
  .trz-front{padding:1.6rem 1rem 3rem}
}

/* =================================================================
 * ANSWER THEME PAGES
 * =================================================================
 * The subject pages under /answer-theme/. Their job is to make the shape of
 * the library visible: how many questions sit here, which are written, which
 * are not, and where the answer ends up as goods.
 *
 * ⛔ THE COLOUR RULE FROM THE REST OF THE SITE APPLIES UNCHANGED: the crimson
 * is for numbers and limits only, never for decoration, never for body text.
 * A figure a reader has not measured and a figure we have are not allowed to
 * look alike, and the same is true of a question we have answered and one we
 * have not.
 */
.trz-answer-head { margin: 0 0 26px; }
.trz-answer-head h1 {
  font-size: 34px; line-height: 1.16; margin: 0 0 10px; color: #16130F;
  letter-spacing: -0.015em; font-weight: 700; max-width: 22em;
}
.trz-answer-lede {
  /* ⛔ 46em was 78 characters a line. The measure is 31em. */
  font-size: 15.5px; line-height: 1.6; color: #3A362F; margin: 0 0 14px;
  max-width:30em;
}
/* The count line. Monospace because it is a figure; crimson because it is the
 * argument the page exists on. */
.trz-asked {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px; color: var(--trz-red); margin: 0; letter-spacing: 0.01em;
}
.trz-asked strong { font-size: 15px; font-weight: 600; }

.trz-theme-direct {
  margin: 0 0 30px; padding: 18px 20px;
  background: #FBFAF7; border: 1px solid #E4E0D6; border-left: 3px solid #16130F;
}
.trz-theme-direct p { margin: 10px 0 0; font-size: 13px; }
.trz-theme-direct a { color: var(--trz-red); }

.trz-block-h {
  font-size: 12px; letter-spacing: 0.10em; text-transform: uppercase;
  color: #5F5E5A; font-weight: 600;
  margin: 34px 0 14px; padding-bottom: 7px; border-bottom: 1px solid #D8D4CA;
}

.trz-qa { margin: 0 0 20px; padding-bottom: 16px; border-bottom: 1px solid #EDEAE2; }
.trz-qa:last-child { border-bottom: 0; }
.trz-qa h3 { font-size: 17px; line-height: 1.35; margin: 0 0 6px; font-weight: 600; }
.trz-qa h3 a { color: #16130F; text-decoration: none; }
.trz-qa h3 a:hover { color: var(--trz-red); }
.trz-qa p { margin: 0; font-size: 14.5px; line-height: 1.58; color: #3A362F; }

/* ⛔ 44em was 78 characters a line. The measure is 31em. */
.trz-honest { font-size: 13px; line-height: 1.6; color: #5F5E5A; margin: 0 0 12px; max-width:30em; }

/* The phrasings somebody typed. ⛔ Answered and unanswered do not look alike:
 * answered is ink, unanswered is grey with a crimson marker, because the
 * difference between them is the whole point of the list. */
.trz-phrasings { list-style: none; margin: 0; padding: 0; }
.trz-phrasings li {
  font-size: 14px; padding: 8px 0 8px 20px; position: relative;
  border-bottom: 1px solid #F0EDE6; color: #3A362F;
}
.trz-phrasings li:last-child { border-bottom: 0; }
.trz-phrasings li.is-answered::before {
  content: ""; position: absolute; left: 2px; top: 15px;
  width: 6px; height: 6px; background: #16130F;
}
/* ⛔ THE FAINTEST INK WAS USED FOR TEXT.
   #8A8578 is the darkest-theme's dimmest ink: on paper it measures
   3.53:1, which is under the floor for text of this size. It is a hairline
   colour -- rules, swatch dots, the dimension line -- and the five rules
   below were using it for words a reader has to read. They now use
   --trz-ink-3, the paper station's own muted ink at 6.02:1. */
.trz-phrasings li.is-open { color: var(--trz-ink-3); font-style: italic; }
.trz-phrasings li.is-open::before {
  content: ""; position: absolute; left: 0; top: 14px;
  width: 8px; height: 8px; background: var(--trz-red);
}

.trz-theme-lead {
  margin: 34px 0 0; padding: 22px 24px;
  background: #FBFAF7; border: 1px solid #E4E0D6;
}
.trz-theme-lead h2 { margin-top: 0; border: 0; padding: 0; }
.trz-theme-lead p { font-size: 14px; line-height: 1.56; color: #3A362F; margin: 0 0 12px; }
.trz-theme-lead ul { list-style: none; margin: 0 0 16px; padding: 0; }
.trz-theme-lead li {
  padding: 9px 0; border-bottom: 1px solid #EDEAE2;
  display: flex; justify-content: space-between; align-items: baseline; gap: 14px;
}
.trz-theme-lead li:last-child { border-bottom: 0; }
.trz-theme-lead li a { color: #16130F; font-size: 15px; font-weight: 500; text-decoration: none; }
.trz-theme-lead li a:hover { color: var(--trz-red); }
.trz-lead-count {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11px; color: var(--trz-red); white-space: nowrap;
}
.trz-lead-count.is-empty { color: #A32D2D; font-style: italic; }

.trz-cta {
  display: inline-block; padding: 12px 22px; background: #16130F; color: #FBFAF7;
  font-size: 13.5px; font-weight: 500; text-decoration: none; letter-spacing: 0.01em;
}
.trz-cta:hover { background: var(--trz-red); color: #FFF; }

.trz-theme-index { list-style: none; margin: 0; padding: 0; }
.trz-theme-index li {
  padding: 10px 0; border-bottom: 1px solid #EDEAE2;
  display: flex; justify-content: space-between; align-items: baseline; gap: 14px;
}
.trz-theme-index li:last-child { border-bottom: 0; }
.trz-theme-index li a { color: #16130F; font-size: 15px; text-decoration: none; }
.trz-theme-index li a:hover { color: var(--trz-red); }

.trz-unwritten { margin: 38px 0 0; padding-top: 20px; border-top: 1px solid #D8D4CA; }
.trz-unwritten ul { list-style: none; margin: 0; padding: 0; }
.trz-unwritten li {
  padding: 7px 0; display: flex; justify-content: space-between;
  align-items: baseline; gap: 14px; font-size: 14px; color: var(--trz-ink-3);
  border-bottom: 1px solid #F4F2ED;
}
.trz-unwritten li:last-child { border-bottom: 0; }

/* =================================================================
 * COLOURWAY LIBRARY (/colourways/)
 * =================================================================
 * Seventy-two swatches on one page. The grid is the whole design: a
 * colourway is chosen by looking at it next to its neighbours, so the
 * pictures have to be big enough to read the chip and close enough to
 * compare. 132px is the narrowest column that still shows a chip pattern
 * at a phone's density; below that a swatch is a colour and nothing else.
 *
 * ⛔ THE CODE IS MONOGRAPHIC ON PURPOSE. It is the catalogue's own number,
 * it is how a buyer who holds the catalogue searches, and a serif or a
 * display face would make a number look like a name. The crimson hover
 * matches the rest of the site: crimson means "this is the live link".
 *
 * ⛔ NO BORDER-RADIUS, NO SHADOW. A swatch with a rounded corner and a
 * drop shadow looks like a product photo of a tile; these are pieces of
 * paper photographed flat, and the page is a chart.
 */
.trz-cw-group { margin: 0 0 6px; }
.trz-cw-group-note { font-size: 12.5px; color: var(--trz-ink-3); margin: -6px 0 14px; }
.trz-cw-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 14px;
  margin: 0 0 8px;
}
.trz-cw-card { display: block; text-decoration: none; min-width: 0; }
.trz-cw-card img {
  display: block; width: 100%; height: auto;
  border: 1px solid #E4E0D6; background: #FBFAF7;
}
.trz-cw-card:hover img { border-color: #16130F; }
.trz-cw-code {
  display: block; margin-top: 6px;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; color: #3A362F; text-align: center; letter-spacing: 0.01em;
}
.trz-cw-card:hover .trz-cw-code { color: var(--trz-red); }

/* The three case photographs. ⛔ One row on the wide screen and one column
 * on a phone: at two-up the landscape floor photograph is 170px wide and
 * the table it shows is smaller than the chips in the grid above it. */
.trz-case-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
  margin: 14px 0 0;
}
.trz-case-fig { margin: 0; min-width: 0; }
.trz-case-fig img {
  display: block; width: 100%; height: auto; border: 1px solid #E4E0D6;
}
.trz-case-fig figcaption {
  font-size: 12.5px; line-height: 1.5; color: #5F5E5A; margin-top: 8px;
}
.trz-case-src { display: block; font-size: 11.5px; color: var(--trz-ink-3); margin-top: 3px; }
@media ( max-width: 720px ) {
  .trz-case-grid { grid-template-columns: 1fr; }
}

/* =================================================================
 * SOURCED FIGURES
 * =================================================================
 * The sealing and repair pages print figures that belong to other people. The
 * attribution is set apart from the table on purpose: same paper, one rule
 * below it, so the eye reads "everything above this line is theirs" without
 * having to read the words.
 *
 * ⛔ The rule is RULE, not crimson. Crimson is the site's marker for a number we
 * are standing behind, and putting it on a borrowed figure would spend the one
 * colour that means something on this site.
 */
.answer-sources {
  margin: 22px 0 0; padding: 18px 20px 16px;
  background: #F7F6F2; border-top: 1px solid #D8D4CA;
}
.answer-sources h3 {
  font-size: 11.5px; letter-spacing: 0.09em; text-transform: uppercase;
  color: #5F5E5A; font-weight: 600; margin: 0 0 10px;
}
/* ⛔ THIS LEDE HAD ITS OWN MEASURE, AND IT WAS ONE CHARACTER OVER.
   44em at 13px measures 79 characters a line. The station's rule is 78,
   and a rule with an exception is a rule with a hole in it -- so the
   number moves to 40em, which measures 72. */
.answer-sources-lede {
  font-size: 13px; line-height: 1.58; color: #5F5E5A; margin: 0 0 12px; max-width:30em;
}
.answer-sources ul { list-style: none; margin: 0; padding: 0; }
.answer-sources li {
  padding: 6px 0 6px 16px; position: relative;
  font-size: 13px; line-height: 1.5; border-bottom: 1px solid #EDEAE2;
}
.answer-sources li:last-child { border-bottom: 0; }
.answer-sources li::before {
  content: ""; position: absolute; left: 2px; top: 13px;
  width: 5px; height: 5px; background: #8A8578;
}
.answer-sources li a { color: #3A362F; text-decoration: none; border-bottom: 1px solid #C9C4B8; }
.answer-sources li a:hover { color: #16130F; border-bottom-color: #16130F; }

/* ⛔ THE SOURCE COLUMN OF THE TABLE ITSELF.
 *
 * A figure and its attribution sit in one row, so a reader scanning down a
 * column reads "interval — who says so — interval — who says so". The column
 * is monospace because it is a citation and not a sentence, and it is grey
 * because it is not a claim we are making.
 */
.answer-table td:last-child:has(> :first-child) { }
.answer-table tr:has(td:nth-child(3):not(:last-child)) td:last-child,
.answer-table td.is-source {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11px; color: #5F5E5A; line-height: 1.45;
}
/* Two rows can carry the same label with different figures — the resealing
 * intervals genuinely conflict between sources — so a repeated source is
 * marked rather than hidden, because the disagreement is the information. */
.answer-table td.is-source.is-disputed {
  color: var(--trz-red); font-weight: 600;
}

/* =================================================================
 * PICTURES ON AN ANSWER PAGE
 * =================================================================
 * Measured before this existed: the sealing answer was 613 words, one SVG and
 * zero photographs. A reader who searched "do terrazzo floors need sealing"
 * was given a table and nothing to look at.
 *
 * ⛔ THE PLACEMENT IS THE DESIGN. Above the table, not below: below, a picture
 * confirms what the numbers already said. Above, it is the reason to read the
 * numbers, and the numbers then describe something they have just seen.
 *
 * ⛔ THE REFERENCE NOTE IS SIZED LIKE THE CAPTION, NOT LIKE A DISCLAIMER.
 * A note in small grey type reads as legal cover. A note in the same size as
 * the caption under the image reads as part of what the image is. This is the
 * difference between a visitor who believes the pictures and a visitor who
 * wonders.
 */
.answer-pictures {
  margin: 28px 0 34px;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
}
.answer-picture { margin: 0; }
.answer-picture img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 3; object-fit: cover;
  border: 1px solid #E4E0D6;
}
.answer-picture figcaption {
  margin: 7px 0 0; font-size: 12.5px; line-height: 1.48; color: #5F5E5A;
}
/* ⛔ The note is crimson because it is a claim about the pictures, not a
 * figure. Same marker as the "not tested" cells: this site uses one colour for
 * the things it will not let a reader take on trust. */
.answer-pictures-note {
  grid-column: 1 / -1; margin: 2px 0 0;
  font-size: 12.5px; line-height: 1.5; color: var(--trz-red);
  border-left: 2px solid var(--trz-red); padding-left: 12px; max-width:30em;
}

/* ⛔ A SINGLE PICTURE IS NOT CENTRED ON A HALF-WIDTH GRID.
 *
 * With auto-fit and one child the single figure stretches the full width, which
 * is a 1400px-wide photograph of a bathroom. A lone picture is capped at the
 * width of two columns so the page keeps its measure. */
.answer-pictures:has(> .answer-picture:only-child) {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
.answer-pictures:has(> .answer-picture:only-child) .answer-picture {
  grid-column: 1; max-width: 620px;
}

@media (max-width: 720px) {
  .answer-pictures { grid-template-columns: 1fr; gap: 22px; }
  .answer-pictures:has(> .answer-picture:only-child) { grid-template-columns: 1fr; }
  .answer-pictures:has(> .answer-picture:only-child) .answer-picture { max-width: none; }
}

/* =================================================================
 * A FORWARDED ANSWER
 * =================================================================
 * Four subjects carry one or two harvested questions each and are answered
 * inside the sequence a buyer walks: where the water comes from, how heavy the
 * slab may be, what separates it into bays, how long it has to last.
 *
 * ⛔ A forwarded answer must not LOOK like an unwritten one. It quotes the
 * direct answer in full and links the page it sits on, so a reader who lands
 * here from the menu reads substance before deciding to click. The note under
 * it explains why the subject has no page of its own, because "we put this
 * somewhere else on purpose" and "we have not done this yet" are different
 * statements and only one of them is true.
 *
 * The crimson is absent here. Nothing on this block is a figure we are
 * standing behind, and the colour is reserved for that.
 */
.trz-alias-note {
  margin: 8px 0 0; font-size: 13px; line-height: 1.55;
  color: #5F5E5A; font-style: italic;
}

/* =================================================================
 * THE CHINESE STANDARD BLOCK
 * =================================================================
 * One answer, given its own heading, because it does not belong to the ranked
 * question list: nobody searches for a standard number, so it has no volume to
 * be ranked by, and inventing a number to place it would break the rule the
 * six above are built on.
 *
 * ⛔ IT IS NOT A SEVENTH QUESTION AND IT DOES NOT LOOK LIKE ONE. The list
 * above is numbered and ranked; this block carries no number, because a rank
 * it cannot justify is the same thing as a fabricated figure.
 *
 * ⛔ THE SOURCING NOTE IS IN THE BLOCK, NOT IN A FOOTNOTE. Thirty-nine of the
 * figures on this site come from other people's documents and the page says
 * so. The one block where the reader might wonder whether we are claiming the
 * standard is the block that states plainly that we hold no certificate.
 */
.trz-standard {
  margin: 30px 0 0; padding: 22px 24px;
  background: #FBFAF7; border: 1px solid #E4E0D6;
  border-left: 3px solid #16130F;
}
.trz-standard-link {
  display: flex; align-items: baseline; gap: 12px;
  text-decoration: none; margin: 0 0 10px;
}
.trz-standard-t {
  font-size: 19px; line-height: 1.34; font-weight: 600; color: #16130F;
}
.trz-standard-link:hover .trz-standard-t { color: var(--trz-red); }
.trz-standard-go { color: var(--trz-red); font-size: 17px; }
.trz-standard-note {
  /* ⛔ 46em was 78 characters a line. The measure is 31em. */
  margin: 0; font-size: 13.5px; line-height: 1.6; color: #3A362F;
  max-width:30em;
}
.trz-standard-src {
  display: block; margin-top: 7px;
  font-size: 12.5px; color: #5F5E5A;
}

/* ==========================================================================
   THE THIN SERIES — 8-12 mm
   --------------------------------------------------------------------------
   The comparison table is the argument, so it is styled as a table and not as
   a set of cards. Six rows of a system-by-system comparison read as a table
   or they read as noise; cards cannot show that the weight column falls by a
   factor of ten from the first row to the last, and that fall is the whole
   reason the thin series exists.
   ========================================================================== */
.thin-table-wrap{
  margin:1.9rem 0 0;overflow-x:auto;-webkit-overflow-scrolling:touch;
}
.thin-table{
  width:100%;border-collapse:collapse;font-size:14.5px;line-height:1.5;
}
.thin-table caption{
  caption-side:top;text-align:left;
  font-size:13px;color:#5F5E5A;padding:0 0 9px;line-height:1.55;
}
/* ⛔ Numbers in the thickness and weight columns get the site's one accent
   colour and monospace. That colour is reserved for figures and ceilings
   everywhere else on this site, and a table whose selling point is a range
   is exactly where spending it is not decoration. */
.thin-table th,.thin-table td{
  padding:9px 12px;text-align:left;border-bottom:1px solid #E4E0D6;
  vertical-align:top;
}
.thin-table thead th{
  font-size:12px;letter-spacing:.055em;text-transform:uppercase;
  color:#5F5E5A;font-weight:600;border-bottom:1px solid #16130F;
  white-space:nowrap;
}
.thin-table td:nth-child(2),
.thin-table td:nth-child(3){
  font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  font-variant-numeric:tabular-nums;white-space:nowrap;
  color:var(--trz-red);font-weight:600;
}
.thin-table td:nth-child(1){font-weight:600;color:#16130F;white-space:nowrap;}
/* ⛔ The row we sell into is marked by a left rule in ink, not in the accent.
   The accent is already saying "these are figures"; using it twice on one row
   would make the marking louder than the numbers it is marking. */
.thin-table tr.is-ours td{background:#F3F0E8;}
.thin-table tr.is-ours td:first-child{box-shadow:inset 3px 0 0 #16130F;}

/* ⛔ The source line sits directly under the table, not in a footer. Somebody
   checking one figure needs the link beside that figure, and every other
   sourcing note on this site is already there for the same reason. */
.thin-source{
  margin:11px 0 0;font-size:12.5px;line-height:1.6;color:#5F5E5A;
  max-width:30em;
}
.thin-source a{color:var(--trz-red);}

/* ⛔ The made-to-order note is set at the same size as the body, because a
   smaller grey sentence reads as a legal disclaimer and this is not one — it
   is the commercial terms of the product, and shrinking it is how a buyer ends
   up ordering something at a thickness we do not build. */
.thin-note{
  margin:1.7rem 0 0;padding:15px 17px;
  background:#FBFAF7;border:1px solid #E4E0D6;border-left:3px solid var(--trz-red);
  font-size:15px;line-height:1.62;color:#3A362F;
}
.thin-note strong{color:#16130F;}

@media (max-width:640px){
  .thin-table{font-size:13.5px;}
  .thin-table th,.thin-table td{padding:7px 8px;}
  .thin-table thead th{font-size:11px;letter-spacing:.04em;}
}

/* ==========================================================================
   THE THIN SERIES BLOCK — the homepage's commercial section
   --------------------------------------------------------------------------
   It sits directly under the six-process drawing, and that adjacency is the
   whole design: the drawing above shows published thicknesses of 20 / 12 / 5 /
   10 / 3 / 9 mm, and the block below answers "where do you fit?". Putting them
   on the same screen is what turns a claim into a comparison.
   ========================================================================== */
.trz-thin{
  margin:34px 0 0;padding:26px 0 0;
  border-top:1px solid #E4E0D6;
}
.trz-thin .trz-block-h{
  margin:0 0 10px;font-size:22px;line-height:1.3;color:#16130F;
}
/* ⛔ 48em was 81 characters a line. The measure is 31em. */
.trz-thin .trz-section-lede{
  margin:0 0 20px;max-width:30em;
  font-size:15.5px;line-height:1.66;color:#3A362F;
}
/* ⛔ The band is set in the site's one accent colour, in monospace, and it is
   the only number allowed to be. Everywhere else on this site that colour means
   "a figure or a ceiling", and this is exactly that: the product claim. */
.trz-thin .trz-section-lede strong{color:var(--trz-red);font-weight:700;}

.trz-thin-figure{margin:0 0 22px;}
.trz-thin-figure svg{
  display:block;width:100%;height:auto;max-width:680px;
}
/* ⛔ SAME RULE AS .trz-figure, AND IT MATTERS MORE HERE.
   This drawing carries the site's only differentiator, and its smallest label
   is 9.5 px — a logarithmic axis tick. Squeezed into a 390 px phone that label
   is 5.4 px. A claim the reader cannot read is not a claim. */
@media (max-width:900px){
  .trz-thin-figure{
    overflow-x:auto;-webkit-overflow-scrolling:touch;
    -webkit-mask-image:linear-gradient(to right,#000 88%,transparent 100%);
    mask-image:linear-gradient(to right,#000 88%,transparent 100%);
  }
  .trz-thin-figure svg{min-width:560px;max-width:none}
}
/* ⛔ 52em was 93 characters a line. The measure is 31em. */
.trz-thin-figure figcaption{
  margin:9px 0 0;max-width:30em;
  font-size:12.5px;line-height:1.62;color:#5F5E5A;
}

/* -- the five products ------------------------------------------------- */
.trz-thin-list{
  list-style:none;margin:0 0 20px;padding:0;
  border-top:1px solid #E4E0D6;
}
.trz-thin-list li{border-bottom:1px solid #E4E0D6;}
.trz-thin-list a{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 14px;
  padding:12px 2px;text-decoration:none;color:inherit;
}
.trz-thin-list a:hover .trz-thin-name{color:var(--trz-red);}
.trz-thin-name{
  flex:1 1 auto;font-size:16px;font-weight:600;line-height:1.4;color:#16130F;
}
.trz-thin-band{
  flex:0 0 auto;font-size:14px;font-weight:700;color:var(--trz-red);
  white-space:nowrap;
}
/* ⛔ The decision variable is what a buyer needs in order to know whether to
   send a specification. It is one line, one size down, and never styled like a
   heading — a variable shouted at in large type reads as the product's name. */
.trz-thin-why{
  flex:1 0 100%;font-size:13px;line-height:1.6;color:#5F5E5A;
  padding-left:1px;
}

.trz-thin-cta{margin:0 0 6px;display:flex;flex-wrap:wrap;gap:12px;}
.trz-thin-cta .btn{
  font-size:14.5px;padding:10px 18px;text-decoration:none;
}

@media (max-width:640px){
  .trz-thin{padding-top:22px;}
  .trz-thin .trz-block-h{font-size:19px;}
  .trz-thin-why{flex:1 0 100%;}
}

/* ==========================================================================
   ⛔ WHY THE SITE DID NOT FIT A PHONE — the one that was actually reported
   --------------------------------------------------------------------------
   BOSS, 2026-10-16: 「为什么我在手机看不了第四站」

   Everything that gets checked first was correct. HTTP 200 on every page, the
   viewport meta present, both stylesheets served with 200, no failed requests,
   no JavaScript errors, and the HTML byte-identical apart from the user agent.

   The cause was this, and it is not a typo — it is the CSS Grid default:

       .gallery { display: grid }        -- its min-width is auto, not 0

   A grid item's `min-width` is `auto`, which means it refuses to be narrower
   than its content. The gallery contained the product picture rail, whose
   slides are `width:78%` — a percentage of a container that had not been given
   a width yet. So:

       .single-grid   390px   (correct — the page container)
       .gallery       547px   (pushed wide by its own content)
       body           390px
       viewport       551px   (the browser widened itself to the content)

   ⛔ AND THE CONSEQUENCE IS NOT A WIDE PAGE, IT IS A PAGE THAT LOOKS BROKEN.
   Once the viewport is 551px on a 390px phone, every full-width element —
   heading, paragraph, the specification table — is laid out for 551px and
   rendered at 390px. Text runs off the right edge and the reader swipes
   sideways to find the rest of a sentence. From the reader's side the site
   does not work, while every automated check says it does.

   ⛔ WHY THE FIX BELOW IS A BLANKET RULE AND NOT 23 EDITS.
   There are 23 `display:grid` containers in this stylesheet and only 7 of
   their items carried `min-width:0`. Adding it to each one would fix today's
   six and leave the other seventeen waiting for the first wide child, which is
   the same class of bug as the shared-theme bug this site already had once:
   fixed everywhere except where nobody looked yet.

   ⛔ THE RULE IS `min-width:0`, NOT `overflow:hidden`. Hiding the overflow
   hides the symptom — the picture rail would stop pushing, and the pictures
   would stop being reachable. min-width:0 lets the item shrink to the column
   it was given, and the rail keeps scrolling inside it, which is the behaviour
   that was designed for it in the first place. */
.single-grid > *,
.single-wrap > .single-grid,
.gallery,
.tax-gallery,
.vb-grid,
.about-pillars,
.cap-split,
.need-body,
.auth-grid,
.acct-grid,
.sc-chain,
.rail-host,
figure.tmq-figure{
  min-width:0;
}

/* ⛔ AND THE PAGE ITSELF MUST BE ALLOWED TO BE NARROW.
   Without this the body can still be pushed by anything not covered above, and
   the symptom returns as "the whole site is too wide" with nothing pointing at
   a cause. `overflow-x:hidden` on the html element is deliberately NOT used
   here: it hides a real overflow instead of fixing it, and it also breaks
   position:sticky inside the page. The rail is fixed by min-width, and this
   only stops a future unanticipated child from turning the whole viewport
   sideways again. */
html,body{max-width:100%}

/* ==========================================================================
   THE PROCESS GRID — six pictures instead of six paragraphs
   --------------------------------------------------------------------------
   BOSS, 2026-10-17: 「首页看起来还是太多文字，我想我们应该图文并茂」.

   Measured before this: 5,913 characters and 1,026 words on the front page with
   ZERO photographs. The six-process block alone carried 1,255 characters in
   six rows, each row a sentence saying what a process is while a drawing of
   its layers sat directly above it.

   ⛔ THE GRID IS NOT DECORATION AND THE LAYOUT REFUSES TO BECOME IT.
   Each cell is a process, and the picture is that process — a precast panel
   under Precast, a resin floor under Epoxy. A buyer recognises a floor faster
   than they read about one, and this is the block where recognition does the
   work. A stock photograph of a staircase next to the word "Poured" would make
   the page look finished and tell the reader nothing, which is worse than the
   text wall it replaced.
   ========================================================================== */
.trz-process-grid{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:16px;
}
.trz-pg{min-width:0}
.trz-pg > a{
  display:flex;flex-direction:column;height:100%;
  text-decoration:none;color:inherit;
  background:#FBFAF7;border:1px solid #E4E0D6;border-radius:3px;
  overflow:hidden;
  transition:border-color .18s ease;
}
.trz-pg > a:hover{border-color:#16130F}

/* -- the picture ------------------------------------------------------- */
.trz-pg-pic{
  display:block;position:relative;margin:0;
  /* ⛔ 4:3 rather than square. A square crop of a floor takes the horizon out
     and leaves an ambiguous patch of texture; 4:3 keeps the junction between
     the floor and the wall, which is what makes a terrazzo floor legible as a
     floor. */
  aspect-ratio:4/3;overflow:hidden;background:#EFEDE7;
}
.trz-pg-pic img{
  display:block;width:100%;height:100%;object-fit:cover;
  transition:transform .28s ease;
}
.trz-pg > a:hover .trz-pg-pic img{transform:scale(1.03)}

/* ⛔ THE CAPTION SITS ON THE PICTURE, NOT UNDER IT.
   Under the picture it becomes a fifth line of text in a grid that was built
   to reduce text. On the picture it is read once, with the image, and it names
   what is visible — which is the whole reason the picture was chosen over a
   stock texture. */
.trz-pg-cap{
  position:absolute;left:0;right:0;bottom:0;
  padding:16px 10px 7px;
  font-size:11.5px;line-height:1.4;color:#F7F5F0;
  background:linear-gradient(to top,rgba(12,11,9,.82),rgba(12,11,9,0));
}

/* ⛔ THE FALLBACK IS THE SECTION DRAWING, IN THE SAME FRAME.
   Porcelain has no photograph in the library and none was invented, so its
   cell shows the layer drawing instead — at the same size, in the same frame,
   so the grid reads as six items rather than five pictures and a gap. */
.trz-pg-draw{
  display:block;aspect-ratio:4/3;overflow:hidden;
  background:#FBFAF7;border-bottom:1px solid #E4E0D6;
  padding:10px 8px;
}
.trz-pg-draw svg{display:block;width:100%;height:100%}

/* -- the text under it, kept to three lines ----------------------------- */
.trz-pg-text{
  display:flex;flex-direction:column;gap:4px;
  padding:11px 13px 13px;flex:1;min-width:0;
}
.trz-pg-name{
  font-size:15.5px;font-weight:600;line-height:1.3;color:#16130F;
}
.trz-pg > a:hover .trz-pg-name{color:var(--trz-red)}
/* ⛔ THE NOTE IS ONE LINE AND CLAMPED.
   It was the sentence that made this block 1,255 characters. Clamping it to
   two lines keeps the sentence that identifies the process and drops the rest,
   and the whole note is one click away on the process's own answer page — which
   is where a buyer who wants the paragraph is already going. */
.trz-pg-note{
  font-size:12.5px;line-height:1.5;color:#5F5E5A;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;
}
.trz-pg-fig{
  margin-top:auto;padding-top:4px;
  font-size:12.5px;font-weight:700;color:var(--trz-red);
}
.trz-pg-fig--none{color:var(--trz-ink-3);font-weight:400;font-style:italic}

/* ⛔ THE REFERENCE DISCLOSURE IS PRINTED ONCE FOR THE WHOLE GRID.
   Repeated under six pictures it is a wall of text inside a picture grid,
   which defeats the reason the grid exists. */
/* ⛔ THIS NOTE HAD A MEASURE OF ITS OWN, AND IT MEASURED 123 CHARACTERS.
   56em at 12px is 672px, and 672px of 12px type is a hundred and twenty
   three characters a line -- three times the line this station reads at.
   It was a caption under a picture grid: the caption is a sentence, and a
   sentence gets the sentence's measure. */
.trz-pg-note-line{
  margin:14px 0 0;font-size:12px;line-height:1.6;color:#5F5E5A;
  max-width:30em;
}

@media (max-width:900px){
  .trz-process-grid{grid-template-columns:repeat(2,1fr);gap:12px}
  .trz-pg-name{font-size:14.5px}
  .trz-pg-note{font-size:12px}
  .trz-pg-cap{font-size:10.5px;padding:14px 8px 6px}
  .trz-pg-text{padding:10px 11px 11px}
}
@media (max-width:520px){
  /* ⛔ ONE column below 520px, not two. Two columns at 320px gives each cell
     140px, which is narrower than the caption under it can wrap to without
     becoming three lines of grey text over a photograph. */
  .trz-process-grid{grid-template-columns:1fr}
}

/* ==========================================================================
   THE OPENING STRIP — six floors, one row, no captions
   --------------------------------------------------------------------------
   ⛔ IT IS A STRIP AND NOT A GRID, and the reason is the height it costs. Six
   tiles side by side at a phone's width is 55px each, which is a thumbnail
   that says nothing. Sideways-scrolled on a phone, they are 200px each and
   legible, and the horizontal scroll is a gesture every phone user already has.
   On desktop six fit without scrolling and it reads as one row of floors.

   ⛔ IT CARRIES NO CAPTION OVERLAYS, unlike the process grid below. The overlay
   there exists to say WHICH PROCESS a picture is; here nothing is being
   identified, so the overlay would be six sentences on the page that was too
   texty. The name sits under the picture in small type and nothing more.

   ⛔ ALL SIX HAVE alt TEXT. The grid captions its pictures and the strip does
   not, which means the strip's pictures would otherwise be the only ones on the
   page described by a name rather than by what is visible. The alt is the
   manifest caption — the sentence a person wrote after looking at the file. */
.trz-strip{
  display:grid;
  grid-auto-flow:column;
  /* ⛔ 240px, NOT 180px. At 180 the strip's height is 132px and object-fit:
     cover crops a floor to a band of texture with no horizon in it — measured,
     four of the six read as near-white rectangles with no subject. 240 keeps
     enough of the picture that a floor is recognisable as a floor. */
  grid-auto-columns:minmax(240px,1fr);
  gap:10px;
  margin:0 0 0;
  overflow-x:auto;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
/* ⛔ min-width:0 ON THE ITEMS, NOT JUST ON THE SCROLLER.
   A grid item's min-width is auto, so `grid-auto-columns:minmax(180px,1fr)`
   makes each tile refuse to be narrower than 180px — and six of those add up to
   more than a 320px screen. The scroller's overflow-x then has nothing to
   scroll, because the scroller itself has already been pushed wide by its own
   children, which is the same failure as the 2026-10-16 product page one day
   later and one level further up the tree.
   ⛔ This is why the blanket min-width:0 rule written yesterday lists its
   selectors instead of matching every grid item: a new grid added today is not
   covered by a rule written for the grids of yesterday. The fix is to remember,
   and the reason the deploy gate rolled the deploy back is that it did not have
   to be remembered by whoever did this. */
.trz-strip > *{min-width:0}
.trz-strip::-webkit-scrollbar{display:none}

/* ⛔ A SCROLLER WITH NO SCROLLBAR IS A SCROLLER NOBODY KNOWS ABOUT.
 *
 * The strip holds six photographs and shows four of them at 1440px: measured,
 * 1490px of content in an 840px window. `scrollbar-width:none` hides the only
 * honest signal that there is more, so the last two pictures are invisible on a
 * page whose whole job is to show that this material exists.
 *
 * ⛔ THE FIX IS A FADE, NOT A SCROLLBAR, AND NOT `overflow:hidden`.
 * A scrollbar on a six-tile strip pushes the layout and reads as a control the
 * site needs. `overflow:hidden` hides the remaining pictures, which is the
 * thing being complained about. A gradient over the right edge says "there is
 * more this way" using no space, and it disappears on its own once the reader
 * has scrolled to the end, which is why it is attached to the container rather
 * than to the content.
 *
 * The mask is what makes it work: a fade painted over the right edge would sit
 * on top of the last tile permanently. Clipping the mask out of the scroller's
 * own box means it stops appearing as soon as nothing is left underneath it. */
.trz-strip{
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 72px),transparent 100%);
          mask-image:linear-gradient(to right,#000 calc(100% - 72px),transparent 100%);
}
/* ⛔ AND ON A SCREEN THAT SHOWS ALL SIX, THE FADE MUST NOT BE THERE.
 * A 72px fade on a strip that is not clipped removes the right edge of the last
 * photograph for no reason, and that is the same "fix a symptom on one screen,
 * break another" pattern this file keeps hitting. */
@media (min-width:1600px){
  .trz-strip{
    -webkit-mask-image:none;
            mask-image:none;
  }
}
/* ⛔ AND ON A PHONE THE STRIP IS A SCROLL BY DESIGN, SO THE FADE MATTERS MOST
 * THERE — six 240px tiles do not fit in 320px and never will. The reader has to
 * be told, and the only place the tell can live is the edge they reach first. */
.trz-strip-i{
  position:relative;display:block;text-decoration:none;
  border-radius:2px;overflow:hidden;background:#EFEDE7;
  /* ⛔ A SHADOW IS NOT A BORDER HERE. This strip sits on the paper background
     of a site that has no other shadows; adding one would make six tiles read
     as floating cards and change the page's character. */
}
.trz-strip-i img{
  /* ⛔ 170px, AND THAT IS THE POINT OF THE 240px COLUMN.
     A floor photographed from standing height is mostly ground. Crop it to a
     132px band and what survives is aggregate texture; give it 170px and the
     junction with a wall or a cabinet comes back into frame, which is the cue
     that says "this is a floor in a room" rather than "this is a pattern". */
  display:block;width:100%;height:170px;object-fit:cover;
  transition:transform .3s ease;
}
.trz-strip-i:hover img{transform:scale(1.04)}
.trz-strip-t{
  position:absolute;left:0;right:0;bottom:0;
  padding:14px 9px 6px;
  font-size:11px;letter-spacing:.03em;color:#F7F5F0;
  background:linear-gradient(to top,rgba(12,11,9,.86),rgba(12,11,9,0));
}
.trz-strip-note{
  margin:9px 0 0;font-size:11.5px;line-height:1.55;color:#5F5E5A;
}

@media (max-width:900px){
  .trz-strip{grid-auto-columns:minmax(210px,1fr);gap:8px}
  .trz-strip-i img{height:150px}
  .trz-strip-t{font-size:10.5px;padding:12px 8px 5px}
}
@media (max-width:520px){
  /* ⛔ 200px on a 320px screen leaves the edge of the next picture showing,
     which is the whole signal that the row scrolls. */
  .trz-strip{grid-auto-columns:minmax(240px,1fr)}
  .trz-strip-i img{height:168px}
}

/* ==========================================================================
   ⛔ CONTENT IMAGES WERE UNCONSTRAINED, AND ONLY WORDPRESS'S OWN RULE COVERED
   THE ONES WITH A CLASS LIKE wp-image-47 IN THEIR NAME
   --------------------------------------------------------------------------
   Found 2026-10-17 by the mobile gate, on the day after it was written.

   The stylesheet had exactly one rule about image width:

       img[class*=wp-image-] { height:auto; max-width:100% }

   ⛔ THAT SELECTOR MATCHES ATTACHMENTS UPLOADED THROUGH THE MEDIA LIBRARY,
   WHERE WORDPRESS PUTS A CLASS SUCH AS wp-image-47 ON THE <img> IT INSERTS.
   It does not match an image rendered by a template, which is how most of the
   pictures on this site arrive: `wp_get_attachment_image()` on a picture whose
   own filename decides its classes, and a raw <img> written into post content.

   Those were served at their natural size. Measured on a 320px phone:

       /answers/terrazzo-thickness/     scrollWidth 1024   IMG.attachment-large
       /products/thin-terrazzo-countertop/  scrollWidth 1024   IMG.
       /products/                        scrollWidth  600   IMG.ph-img

   ⛔ AND 1024 IS NOT A TYPO, IT IS THE UPLOAD. The reference photographs are
   imported at 1024px, which is correct on a desktop and is three times a phone
   screen. Nothing told the browser to bring it down, so the document became
   1024px wide and the phone was asked to render a desktop page.

   ⛔ WHY NOBODY CAUGHT IT BEFORE. Every page that overflowed was one where the
   overflowing element was an <img>, and the first version of the mobile gate
   asked "which element is widest" — an image inside a scroll container answers
   that question loudly and correctly while the document width stays fine. The
   three pages it flagged were flagged for the wrong reason until the report was
   read: the culprit was the picture, not the block it sat in.

   ⛔ THE RULE IS max-width:100%, NOT A WIDTH. max-width lets a small picture
   stay small; width:100% would blow every 120px thumbnail up to the column. */
.answer-body img,
.single-content img,
.single img,
article img,
.ph-img,
figure img{
  max-width:100%;
  height:auto;
}
/* ⛔ AND THE FIGURE THAT HOLDS IT MUST NOT BE PUSHED WIDE BY THE PICTURE.
   Same min-width:auto trap as the grid items on 2026-10-16, one level down:
   a figure is a block, and a block containing a 1024px image grows to match. */
.answer-body figure,
figure img{max-width:100%}
.answer-body img,
.single img{
  /* ⛔ display:block is what stops the inline-baseline gap that leaves four
     stray pixels under every picture. It is a one-pixel fix that is otherwise
     invisible in a screenshot and is read as "the layout is off" by anyone
     looking at it. */
  display:block;
}

/* ==========================================================================
   ANSWER-PAGE DRAWINGS SCROLL ON A PHONE, FOR THE SAME REASON THE HOME PAGE
   ONES DO
   --------------------------------------------------------------------------
   ⛔ BOTH DRAWINGS ADDED WITH WAVE 2 CARRY 10-12 px TEXT.
   At width:100% inside a 390 px phone, a 680-unit drawing scales to 57% and a
   10 px label becomes 5.7 px — present, correct, and unreadable. The chip
   ceilings on these pages are the answer, so the numbers being too small to
   read defeats the drawing.

   ⛔ min-width:560px, the same figure the home page drawings use, and for the
   same reason: it is a width at which the labels in these drawings are
   legible rather than a width that stops an overflow.
   ========================================================================== */
@media (max-width:900px){
  .answer-figure{
    overflow-x:auto;-webkit-overflow-scrolling:touch;
    -webkit-mask-image:linear-gradient(to right,#000 88%,transparent 100%);
    mask-image:linear-gradient(to right,#000 88%,transparent 100%);
  }
  .answer-figure svg{min-width:560px;border:0}
  .answer-figure figcaption{position:relative;z-index:1}
}

/* ============================================================================
   APPLE'S DISPLAY STYLE, MEASURED AND BORROWED
   ============================================================================
   BOSS, 2026-10-21: "页面显示的文字看不清, 咱们可以好好学习下Apple.com网站的
   显示风格" — after finding the password-reset confirmation unreadable.

   ⛔ WHAT WAS MEASURED, NOT REMEMBERED
   The numbers below were read out of Apple's own stylesheet in a browser
   (getComputedStyle on apple.com), not recalled from memory:

       body      17px / 400 / 25px line / -0.374px tracking / #1D1D1F
       h2        56px / 600 / 60px line / -0.28px tracking
       paragraph 21px / 400 / 25px line / +0.231px tracking
       buttons   17px / 400 / 20px line / -0.374px / radius 980px
       link      rgb(0,102,204)

   ⛔ WHAT IS BORROWED AND WHAT IS NOT
   Borrowed, because it is about legibility and it is what "Apple's style"
   means to a reader:
     · the system font stack first, so the page renders in SF on a Mac and
       Segoe/Roboto elsewhere, instead of Helvetica Neue, whose thin strokes
       at 13px are the reason small print looks faint here;
     · NEGATIVE tracking on body and headings. Apple tightens (-0.374px at
       17px) because its faces are drawn to be set that way. This station
       was tracking OUTWARD (+0.08px) on body text, which is the opposite
       of what Apple does and reads as loose;
     · 600 for headings, not 700. Apple's large headings are semibold, and
       700 at 34px is heavier than the reference;
     · 17px body, 25px line, and a measure that stays under 75 characters.

   NOT borrowed, on purpose:
     · the palette. This station's warm paper ground and gold accent are
       the brand, and Apple's white-and-blue is not a better brand for a
       stone supplier;
     · the pill button (radius 980px). A 10px radius on a gold block reads
       as machined; a full pill reads as a consumer app;
     · 56px section headings. Apple's 56px sits on full-bleed photography;
       here it would be a headline on a white sheet.

   ⛔ WHY THE MEASURE IS THE POINT, NOT THE SIZE
   2026-10-19 measured this and it still holds: 18px pushes the line past
   75 characters and long paragraphs get harder to read, not easier. So the
   size moves to Apple's 17px and the measure is held at the same time.
   ========================================================================== */
body.trz{
  /* The system stack, Apple's order, with the old face kept only as a
     fallback for a machine that has none of the first three. */
  font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display","Segoe UI",Roboto,Helvetica,Arial,"PingFang SC","Microsoft YaHei",sans-serif;
  /* Apple's body: 17px on a 25px line. */
  font-size:17px;
  line-height:1.47;
  /* Apple's tracking is negative. This station was tracking outward, which
     reads as loose rather than as airy. */
  letter-spacing:-.006em;
}

/* ⛔ THE HEADINGS WERE SET AT 700.
   Apple's large headings are 600: semibold, not bold. At 34px on paper a
   700 heading is a slab; at 600 it is a headline. */
body.trz h1,
body.trz h2,
body.trz h3{
  font-weight:600;
  /* Apple's headings tighten more than its body text. */
  letter-spacing:-.018em;
}

/* ⛔ THE SMALL PRINT IS WHERE THE FATIGUE LIVES.
   A 12px caption is small; a 12px caption that is also 3.5:1 is the
   combination that tires a reader quickest. The station's own muted ink
   (--trz-ink-3, 6.02:1) is used for anything under 14px, and the size
   itself is lifted one step so a caption is not smaller than a label. */
body.trz .chip,
body.trz .kicker,
body.trz .trz-fig,
body.trz .eyebrow,
body.trz .sub,
body.trz figcaption,
body.trz .fine{color:var(--trz-ink-3)}

/* ⛔ THE SYSTEM-MESSAGES WERE PAINTED FOR A DARK SITE.
   `.notice.ok` and `.notice.err` are how the site says "that worked" and
   "that did not". Their text colours were the dark stations' light tints:

       .notice.ok   #cdeed4 on a 10% green wash over paper  ->  1.32:1
       .notice.err  #f3c4bc on a 14% red wash over paper   ->  1.50:1

   The password-reset confirmation is one of these, and it is the sentence
   that tells a buyer whether to go and open their mail. A pale green
   sentence on a pale green wash is not a message.

   The ground stays a wash of the same hue -- it is a system message and
   should look like one -- and the ink becomes the dark side of the same
   hue, which is what the wash was meant to sit under:

       ok   ink #1E5B3A on the 14% green wash  ->  6.63:1
       err  ink #8C2F22 on the 13% red wash    ->  6.49:1
       link #1E5B3A, underlined, so a link inside the message is still a link
*/
body.trz .notice.ok{
  background:rgba(120,200,140,.14);
  border-color:#5DA97A;
  color:#1E5B3A;
}
body.trz .notice.ok a{color:#1E5B3A;text-decoration:underline}
body.trz .notice.err{
  background:rgba(224,108,90,.13);
  border-color:#C9705F;
  color:#8C2F22;
}
body.trz .notice.err a{color:#8C2F22;text-decoration:underline}

/* ⛔ THE STATUS PILLS ON /my-account/ HAD THE SAME FAULT.
   "Approved" and "Rejected" were written in the same pale tints as the
   notices, inside a pill whose own ground is a paper tint -- so the two
   words that tell a buyer where their application stands were the least
   readable text on the page. */
body.trz .pill.p-ok{
  background:rgba(120,200,140,.16);
  border-color:#5DA97A;
  color:#1E5B3A;
}
body.trz .pill.p-no{
  background:rgba(224,108,90,.15);
  border-color:#C9705F;
  color:#8C2F22;
}

/* ⛔ THE SEPARATOR WAS A HAIRLINE COLOUR USED AS A WORD.
   `·` between "Forgot your password?" and "Create an account" was set in
   the rule colour -- the same value used for 1px borders -- which is a
   decoration, not a letter. On the account card it measured 1.32:1 and the
   separator vanished. A separator is punctuation: it is read, so it is
   given the ink the surrounding words have. */
body.trz .auth-alt .sep{color:var(--trz-ink-3)}
/* ⛔ AND THE DOT IN THE NAVIGATION, THE SAME FAULT, FOR THE SAME REASON.
   The rule colour is a decoration; a dot the reader is meant to see is
   text. It does not render on this station today, but the shared
   stylesheet has it and this fork mirrors the shared stylesheet, so
   leaving the two different is how the two drift apart. */
body.trz .nav-dot{color:var(--trz-ink-3)}
body.trz .answer-crumb .sep{color:var(--trz-ink-3)}

/* ============================================================================
   THE MEASURE: THE LINE LENGTH, NOT THE SIZE
   ============================================================================
   2026-10-19 measured this on the third station and wrote it down: "⛔ 不是
   18px: 18px 会把行长推过 75 字符, 长段落更难读。痛点是行长不是字号。"

   ⛔ AND THE FOURTH STATION HAD THE SAME DEFECT, MEASURED
   On /about/ the prose ran the full width of the container:

       body paragraph   852-860px wide   =   84 characters a line
       lead paragraph   841px wide       =   81 characters a line

   Eighty-four characters a line is past the point where the eye can find
   the next line without effort, and it is why a page can be set in a
   perfectly readable colour and still tire the reader. The 10-19 note
   already said what the fix is: the measure, not the size.

   ⛔ WHY 70ch AND NOT A PIXEL VALUE
   `ch` is the width of the "0" glyph, so it follows the font and the size
   instead of freezing one screen's arithmetic into the stylesheet. Measured
   on this station at 17px, 1ch = 10.19px, so:

       70ch = 713px = about 70 characters

   which is inside the 65-75 range Apple's own prose sits in. A pixel value
   would be right at 17px and wrong the moment the size moves.

   ⛔ WHAT IS NOT TOUCHED
   The size stays at Apple's 17px. The blocks that are not prose -- a spec
   table, a product grid, a figure caption, a chip -- keep their own width,
   because a measure is for sentences and a table is not a sentence.
*/
/* ⛔ THE SELECTOR HAS TO NAME THE REAL ANCESTOR.
   The first attempt wrote `.single-wrap > p` and it matched nothing: the
   paragraph's parent is DIV.single, and .single-wrap is its grandparent.
   A rule that matches no element is not a narrow rule -- it is no rule,
   and the page measured 84 characters a line exactly as before.

   ⛔ AND THEN THE SECOND ATTEMPT NAMED ONE ANCESTRY AND STILL MISSED MOST
   Measuring the over-long paragraphs on six pages found twenty different
   ancestries for the same defect -- .kb-faq-item, .cap-block, .sc-specs,
   .answer-why, .need-main, .single, .sc-hero -- and writing twenty
   selectors is how a rule stops being a rule. A paragraph is a paragraph
   whichever box it sits in, so the measure is applied to the paragraphs
   themselves.

   ⛔ THE EXCLUSIONS ARE THE POINT
   A measure is for sentences. It is NOT for:
     · a table cell      -- a table is a grid, its width is its content
     · a caption         -- a caption is a label, it should be short
     · a chip or a pill  -- a badge is a word, not a line of prose
     · a product card    -- a card is a grid of facts
   So those are excluded by name, and everything else that is a paragraph
   gets the measure.

   ⛔ WHY em AND NOT ch, MEASURED
   The first attempt wrote `70ch`. It is the wrong unit for this job, and
   the page said so: `ch` is the width of the glyph "0", which is wider
   than an average letter, so 70ch is 70 ZERO-WIDTHS, not 70 characters.
   At 17px, 70ch = 713px, which measured 89 characters a line -- the
   paragraph was still too long, and the rule looked like it had worked.

   The unit that answers the question is the one that counts the letters.
   Measured on this station, with real prose in a real column:

       15px  ->  700px holds 100 characters
       16px  ->  700px holds  95 characters
       17px  ->  700px holds  89 characters
       18px  ->  700px holds  87 characters

   `em` rather than px because a px value is right at exactly one size and
   wrong at every other; the lead on /about/ is 18px while the body is
   17px, and a single rule has to serve both.

   ⛔ AND THE NUMBER WAS MEASURED TWICE, AND THE SECOND TIME IT WAS
   SMALLER, BECAUSE THE FIRST TIME IT WAS WRONG.
   The first calibration put a sample sentence in a column and counted the
   characters that fitted: 33.5em, and it was too generous, because the
   sample's letters were not the site's letters. At 33.5em the real prose
   measures 77 to 83 characters a line -- over the ceiling.

   The second calibration used the pages' own text: a paragraph is copied
   into a probe of its own width and the browser is asked where the line
   breaks. Measured on the live station:

       .fine            12.5px   419px   83 characters   needs 31.5em
       .need-sub        14.5px   486px   81 characters   needs 32.3em
       body paragraph   15.0px   504px   80 characters   needs 32.7em
       body paragraph   17.0px   570px   80 characters   needs 32.7em
       .answer-sources  13.0px   436px   79 characters   needs 33.1em

   The tightest requirement is the SMALLEST type, so 30em is the number,
   and every other size lands between 72 and 77 characters -- inside
   Apple's 65-75 range and the project's 78 ceiling.

   ⛔ AND A GATE NOW MEASURES IT, SO THE NUMBER CANNOT DRIFT QUIETLY.
   tools/trz_measure_gate.py counts the characters on the first line of
   every paragraph on every page, using the text the paragraph actually
   has, and fails at 78. A number in a comment is a claim; this is a
   measurement. */
body.trz p,
body.trz .lead,
body.trz .lede,
body.trz .sub,
body.trz .prose,
body.trz .answer-direct,
body.trz .trz-answer-lede{max-width:30em}

/* ⛔ EVERY MEASURE IN THIS STATION WAS ON THE WRONG UNIT, AND IT TOOK A
   MEASURING GATE TO FIND OUT.
   Nineteen prose blocks in this stylesheet set their width in `ch`, which
   is the width of the glyph "0". A line of prose is made of letters, and a
   zero is wider than most of them, so `ch` quietly measures a line of
   zeros rather than a line of words. Two of them were caught by eye:

       .trz-section-lede   60ch at 16px  =  744px  =  123 characters
       .trz-front-lede     62ch at 16.3px = 547px =  74 characters

   and the same error was in fifteen more that nobody had looked at. They
   now all use 31em, the figure measured at every size this site sets.

   The two `ch` measures that remain are the two headings, and they are
   left alone on purpose: a heading is set to break early, and a heading's
   measure is a design decision rather than a reading one. */
body.trz .answer h1,
body.trz .trz-front-h1{max-width:24ch}

/* ⛔ AND THE THINGS THAT ARE NOT SENTENCES KEEP THEIR OWN WIDTH. */
body.trz td,
body.trz th,
body.trz figcaption,
body.trz .chip,
body.trz .kicker,
body.trz .eyebrow,
body.trz .pill,
body.trz .trz-fig,
body.trz .cw-card,
body.trz .dl-card,
body.trz .spec-table,
body.trz .label,
body.trz .value{max-width:none}

/* ============================================================================
   THE WHATSAPP LINE, AND THE GREEN IT IS DRAWN IN
   ============================================================================
   BOSS, 2026-10-21: "把我们四个站的联系方式统一先加上whatsapp
   0086+18150518896" -- one number on all four stations, so an enquiry that
   arrives anywhere reaches the same person.

   ⛔ THE BRAND GREEN IS A DARK-SITE COLOUR, AND THIS IS A PAPER STATION.
   The WhatsApp green #25D366 is drawn as the ring around the telephone
   glyph and as the label on hover. On the three dark stations it is a
   bright mark on a dark ground and it reads. On this station's paper:

       #25D366 on #FBFAF7 (page)    1.90:1
       #25D366 on #FFFFFF (card)    1.98:1
       #25D366 on #F4F2ED (panel)   1.77:1

   A ring at 1.9:1 is a smudge, and a hover label at 1.9:1 is a label
   nobody can read -- so the number would have been on the page and
   unusable, which is worse than not having put it there.

   ⛔ THE DARKER GREEN IS THE SAME HUE, NOT A DIFFERENT COLOUR.
   #1B7F3E is the WhatsApp green taken down the same hue until it passes:

       on #FBFAF7   4.85:1      on #FFFFFF  5.06:1
       on #F4F2ED    4.52:1

   The icon ring is a graphic and needs 3:1; the label is text and needs
   4.5:1. One value clears both, so the ring and the label are the same
   green and they match each other.

   ⛔ ONLY THIS STATION. The three dark stations keep #25D366, because the
   colour that is right on paper is the wrong one on a dark ground. */
body.trz .contact-strip .cs-wa .cs-ico{
  border-color:#1B7F3E;
}
body.trz .contact-strip .cs-wa .cs-ico::before{
  border-left-color:#1B7F3E;
  border-bottom-color:#1B7F3E;
}
body.trz .contact-strip .cs-wa:hover{
  border-color:#1B7F3E;
  color:#1B7F3E;
}
body.trz .nav-wa{color:#1B7F3E}
body.trz .nav-wa .wa-ico{border-color:#1B7F3E}
body.trz .nav-wa:hover{background:rgba(27,127,62,.10);border-color:rgba(27,127,62,.45)}

/* ============================================================================
   THE HEADINGS, IN THE SAME APPLE WEIGHT THE OTHER THREE STATIONS USE
   ============================================================================
   BOSS, 2026-10-21: "我们这四个站的显示风格全部参照apple.com网站的风格来
   修改下" -- the four stations are to read the same way.

   ⛔ THIS FORK'S HEADING RULES ARE NOT THE SHARED ONES, AND THE FIRST
   ATTEMPT AT THIS MISSED THEM.
   The shared stylesheet's headings are `.hero h1`, `.section-head h2`,
   `.tax-head-txt h2` and a dozen more; this station's fork has those AND
   six of its own -- `.trz-front-h1`, `.trz-answer-head h1`, `.dl-head h1`,
   `.kb-head h1`, `.need-hero h1`, `.sc-hero h1`, `.cap-hero h1`,
   `.smp-hero h1`. So setting the weight on the shared list changed the
   shared stations and left this one at 800, and the two files drifted
   apart on the same afternoon.

   That is what tools/check_apple_typography.py exists for: it reads the
   weight out of the rule that sets it in BOTH files and compares them,
   and it caught this within a minute of being written.

   ⛔ APPLE'S HEADINGS ARE 600, NOT 700 AND NOT 800.
   At 38px a 700 heading is a slab and an 800 one is a wall. Apple sets
   its display type at 600 and lets the body stay the quieter of the two.

   ⛔ AND THE QUESTION HEADINGS KEEP THEIR OWN WEIGHT, ON PURPOSE.
   `.answer h1` is a question somebody typed, and it is set at 500 so it
   reads as a question rather than as a headline. That is a reading
   decision, not a brand one, and it is left alone.
*/
.hero h1,
.section-head h2,
.tax-head-txt h2,
.single h1,
.auth-intro h1,
.acct-head h1,
.need-hero h1,
.sc-hero h1,
.cap-hero h1,
.smp-hero h1,
.dl-head h1,
.kb-head h1,
.lead-card-body h2,
.kb-lead-body h2,
.kb-body h2,
.kb-body h3,
.kb-body h4,
.kb-card-body h3,
.dl-name,
.trz-front-h1,
.trz-answer-head h1,
.trz-answer-h2,
.trz-section-h2,
.trz-block-h{font-weight:600}

/* ⛔ AND THE HEADINGS TIGHTEN MORE THAN THE BODY DOES.
   Apple's display type tightens by -0.28px at 56px; scaled to the sizes
   these stations use, -0.018em is the same gesture. The rules that
   already carried a tighter tracking of their own -- the answer
   question, the front sentence -- keep it, because those are set to a
   deliberate width. */
.hero h1,
.section-head h2,
.tax-head-txt h2,
.single h1,
.auth-intro h1,
.acct-head h1,
.need-hero h1,
.sc-hero h1,
.cap-hero h1,
.smp-hero h1,
.dl-head h1,
.kb-head h1,
.lead-card-body h2,
.kb-lead-body h2,
.kb-body h2,
.kb-body h3,
.kb-body h4,
.kb-card-body h3,
.dl-name,
.trz-answer-head h1{letter-spacing:-.018em}

/* ============================================================================
   THE LINKS THAT CARRY THEIR OWN COLOUR, AND THE RULE THAT STEALED IT
   ============================================================================
   ⛔ ONE RULE WAS BREAKING THREE CONTROLS AT ONCE, AND A FULL-SITE SWEEP
   FOUND ALL THREE.

   `body.trz a{color:var(--gold-soft)}` gives every link on this station
   the gold-soft colour. It is specificity 0,1,1. Three controls set their
   own colour in a single class -- 0,1,0 -- and lost:

       .btn-submit   the product page's "Post Your Needs for this material"
                     gold label on a gold gradient      ->  1.19:1
       .trz-cta      the answer page's "Send us the specification"
                     gold label on a near-black block  ->  3.18:1
       .nav a.nav-pyn  the "Post Your Needs" pill in the header
                     gold label on a 10% gold wash    ->  3.18:1

   ⛔ 262 + 10 pages carried the first two, and every one of them showed
   a control that was painted but could not be read. The sweep that found
   them is tools/trz_fullsite_readability.py, which walks all 524 URLs of
   this station; the earlier gates had only ever looked at a list of
   pages somebody chose.

   ⛔ THE FIX IS PRIORITY, NOT A NEW COLOUR
   Each of these three already says what colour its label is. The fix is
   to give those declarations the same specificity as the rule that was
   beating them -- `body.trz` in front of the class makes them 0,2,1 --
   and to change no colour at all. The label on a gold block is the dark
   one it was always supposed to be.
*/
/* ⛔ AND THE BUTTON PAINTS ITS OWN GOLD, THE WAY .dl-go DOES.
   The button's gradient ran from --gold to --gold-deep, and on this
   station --gold-deep is the deep gold the links use (#6F561A). A dark
   label on that end measures 2.64:1, so the label was unreadable at one
   end of the button and the gate could not say which end, because a
   gradient has no single ground.
   The download button was already given the answer: a SOLID gold with a
   dark label. The same ground gives one number, and the number holds:
   #FBFAF7 on #8A6D1F is 4.69:1.
   ⛔ A GRADIENT ON A CONTROL IS A DECORATION THAT COSTS THE LABEL ITS
   GROUND. One ground, one contrast, one verdict. */
body.trz .btn-submit{background:#8A6D1F;color:#FBFAF7}
body.trz .btn-submit:hover{background:#6B5417;color:#FBFAF7}
body.trz .trz-cta{color:#FBFAF7}
body.trz .nav a.nav-pyn{color:#6B5417}
body.trz .nav a.nav-pyn:hover{color:#1a1405}

/* ⛔ AND THE RED WAS 0.04 SHORT OF THE FLOOR.
   --trz-red is the station's crimson: the honest line on a question that
   has no published answer, and the hover colour of the answer page's
   call to action. On the paper ground var(--trz-red) measured 4.46:1 against a
   4.5 floor -- a rounding error, and the kind that hides behind every
   other finding. #B93F2B measures 4.78:1 and is the same colour to the
   eye. */
/* The crimson was moved in the variable above, and every rule that used
   to name it outright now names the variable, so this station has one
   red instead of two. */

/* ==========================================================================
   THE PICTURES ON THE FRONT PAGE
   ==========================================================================
   BOSS, 2026-10-22: the front page was all text — 0 images against 54 prose
   blocks — and six other pages carried no picture at all, while 209
   photographs of terrazzo this company installed sat unused in the library.

   Two blocks: a band of four project photographs that link to the case
   articles, and a strip of eight colourways that link to the product pages.
   Both are placed AFTER the six questions, which are the reason a reader
   arrives; the pictures are the evidence that the answers come from material
   somebody has actually installed.

   ⛔ EVERY COLOUR BELOW IS ONE OF THE STATION'S OWN VARIABLES.
   The contrast gate on this station measures pairs, and a literal hex in a
   new rule is a pair the gate will read but a later palette change will not
   move. The crimson once sat 0.04 below the floor for exactly this reason.

   ⛔ AND EVERY TEXT COLOUR IS MEASURED AGAINST var(--trz-paper), NOT AGAINST
   A CARD. The cards sit on the paper ground with no fill of their own, so
   the ground under these labels IS the paper. That is the easy case, and it
   is the case worth stating, because the moment a card grows a background the
   ground changes and the numbers stop applying. The one exception is
   .trz-swatch-more, which is filled, and its numbers are stated inline.
   ========================================================================== */

/* ---------- shared heading block ---------- */
.trz-shots-head{
  margin:0 0 1.15rem;
}
.trz-shots-note{
  margin:.5rem 0 0;
  font-size:.9375rem;
  line-height:1.5;
  color:var(--trz-ink-3);
  max-width:52ch;
}

/* ---------- the project band ---------- */
.trz-shots{
  margin:2.75rem 0 0;
  padding:2.25rem 0 0;
  border-top:1px solid var(--trz-rule);
}

.trz-shot-grid{
  list-style:none;
  margin:0;
  padding:0;
  display:grid;
  /* Four across on a desktop, two on a tablet, one on a phone.
     ⛔ minmax(0, 1fr), NOT minmax(<length>, 1fr).
     A grid item's automatic minimum size is its content, and an <img> with
     a srcset is content — so a track declared as minmax(220px, 1fr) refuses
     to shrink below 220px and pushes the whole grid wider than the viewport
     on a phone. min-width:0 on the item does the same job for flex. */
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:1.25rem;
}

.trz-shot{margin:0;min-width:0}

.trz-shot-link{
  display:flex;
  flex-direction:column;
  /* The card has no background. It is a picture, a caption and a rule, and a
     filled card on this station would read as a different site. */
  color:var(--trz-ink);
  height:100%;
}

.trz-shot-fig{
  display:block;
  position:relative;
  overflow:hidden;
  border-radius:10px;
  background:var(--trz-paper-3);
  /* 4:3 matches the tmq-card size these are requested at, so the browser is
     not scaling a cropped 600x450 up into a taller box and softening it. */
  aspect-ratio:4/3;
}
.trz-shot-img{
  width:100%;
  height:100%;
  object-fit:cover;
  display:block;
  /* The photographs are the point of the block; no motion on them at all.
     A slow zoom on hover reads as a shop. This is a specification site. */
  transition:none;
}
.trz-shot-link:hover .trz-shot-img{opacity:.92}

.trz-shot-txt{
  display:block;
  padding-top:.7rem;
}

.trz-shot-kind{
  display:block;
  font-size:.75rem;
  line-height:1.3;
  letter-spacing:.06em;
  text-transform:uppercase;
  /* --trz-ink-3 on --trz-paper: 5.6:1. Small, spaced, quiet — it is a
     category label, and it must not compete with the building name. */
  color:var(--trz-ink-3);
  margin-bottom:.28rem;
}

.trz-shot-t{
  display:block;
  font-size:1rem;
  line-height:1.36;
  font-weight:590;
  letter-spacing:-.011em;
  color:var(--trz-ink);
}

.trz-shot-go{
  display:block;
  margin-top:.3rem;
  font-size:.8125rem;
  line-height:1.4;
  color:var(--trz-red);
}
.trz-shot-link:hover .trz-shot-t{color:var(--trz-red)}

/* ---------- the colourway strip ---------- */
.trz-swatches{
  margin:2.5rem 0 0;
  padding:2.25rem 0 0;
  border-top:1px solid var(--trz-rule);
}

.trz-swatch-row{
  list-style:none;
  margin:0;
  padding:0;
  display:flex;
  flex-wrap:wrap;
  gap:.9rem;
}

.trz-swatch{
  margin:0;
  min-width:0;
  /* ⛔ flex:1 1 0, NOT a width in a calc against an assumed container.
   *
   * The first version of this rule was
   *     width: calc((100% - 8.1rem) / 9)
   * written against a container believed to be 1200px. Measured on the live
   * page it is 840px — this station's prose column, not the theme's --maxw,
   * because the front page runs inside the reading column. So nine tiles came
   * out at 78.9px each, which is 631px of tiles plus eight 14.4px gaps =
   * 746px, and the 128px "all" tile then had 94px left and wrapped onto a
   * second row by itself. A dark tile alone on a line reads as a mistake,
   * not as a link.
   *
   * flex:1 1 0 makes all nine share whatever the container is, so the row is
   * correct at 840px, at 1160px and at 375px without a second number being
   * invented. The "all" tile takes the same width as a swatch, which is also
   * what makes the row read as nine things rather than eight and an aside. */
  flex:1 1 0;
}

.trz-swatch a{
  display:block;
  color:var(--trz-ink);
}

.trz-swatch-fig{
  display:block;
  overflow:hidden;
  border-radius:8px;
  background:var(--trz-paper-3);
  /* ⛔ 4:5, NOT the source ratio, and that is the whole point.
     The three supplier families disagree: Dongxing crops are 950x1400
     portrait, Pengxiang slabs are landscape, Runpin is near-square. Sized
     from the file, one row would be three heights and the strip would read
     as three unrelated widgets. A fixed box with object-fit:cover makes the
     crop a decision this stylesheet makes once, on purpose, instead of a
     thing that happens differently per file. */
  aspect-ratio:4/5;
}
.trz-swatch-img{
  width:100%;
  height:100%;
  object-fit:cover;
  display:block;
}
.trz-swatch a:hover .trz-swatch-img{opacity:.92}

.trz-swatch-t{
  display:block;
  margin-top:.45rem;
  font-size:.8125rem;
  line-height:1.3;
  font-weight:590;
  letter-spacing:.01em;
  /* The supplier's code. It is the only part of this card a buyer can write
     down and ask for again, so it is set in ink, not in the muted tone. */
  color:var(--trz-ink);
  font-variant-numeric:tabular-nums;
}
.trz-swatch a:hover .trz-swatch-t{color:var(--trz-red)}

/* ---------- the "all colourways" tile ---------- */
/* The one filled element in this block, so it is also the one with a
   different contrast problem: #FBFAF7 on #16130F is 16.9:1. The rule is
   declared here rather than inherited because the ground is this element's
   own, not the page's. */
/* ⛔ THE FILLED TILE IS AN <li> WRAPPING AN <a>, AND BOTH OF THEM
 * REFUSE TO SHRINK — WHICH IS WHY THE FIX HAS TO BE ON BOTH.
 *
 * The swatch row is a flex row and its items are the <li>s. On a phone
 * the media query gives every .trz-swatch a basis of
 * calc((100% - 2.7rem) / 4) — a quarter of the row — so the four tiles
 * sit side by side at 61px each inside a 288px row.
 *
 * The filled tile is an <li class="trz-swatch trz-swatch-more">, and
 * the anchor inside it carries the text. Two things refuse to shrink:
 *
 *   · the <li> is a flex item, and a flex item's default min-width is
 *     auto, so it will not go below its own content;
 *   · the <a> inside it is a block whose width is its content's width
 *     ("All products" plus an arrow is 121px), and the <li> inherits
 *     that floor through min-width:auto.
 *
 * So the <li> is 61px of row but its anchor is 121px, and the anchor
 * is what the reader sees — 60px past the right edge of a 320px phone.
 *
 * ⛔ AND THE CONSEQUENCE IS NOT A WIDE PAGE, IT IS A BROKEN-LOOKING ONE.
 * The browser widens its own viewport to the content, and every
 * full-width element on the page is then laid out for the wrong width.
 * This is the same class of fault as the grid min-width:auto one this
 * project has already paid for twice.
 *
 * The fix: min-width:0 on the <li>, on the anchor, and on the two
 * spans inside it, plus width:100% on the anchor so it fills the tile
 * it is in instead of being as wide as its text.
 */
.trz-swatch-more{
  min-width:0;
}
.trz-swatch-more a{
  display:flex;
  flex-direction:column;
  justify-content:flex-end;
  gap:.35rem;
  min-height:100%;
  aspect-ratio:4/5;
  padding:.85rem .8rem;
  border-radius:8px;
  background:var(--trz-ink);
  color:#FBFAF7;
  min-width:0;
  width:100%;
  overflow-wrap:anywhere;
}
.trz-swatch-more-t,.trz-swatch-go{min-width:0;overflow-wrap:anywhere}
.trz-swatch-more-t{
  font-size:.875rem;
  line-height:1.32;
  font-weight:590;
  letter-spacing:-.008em;
  color:#FBFAF7;
}
.trz-swatch-go{font-size:.8125rem;color:#FBFAF7;opacity:.82}
.trz-swatch-more a:hover{background:var(--trz-ink-2)}
.trz-swatch-more a:hover .trz-swatch-more-t{color:#FBFAF7}

/* ---------- focus, in the keyboard's colour ---------- */
.trz-shot-link:focus-visible,
.trz-swatch a:focus-visible{
  outline:2px solid var(--trz-red);
  outline-offset:3px;
  border-radius:10px;
}

/* ---------- narrow screens ---------- */
@media (max-width:1000px){
  /* Two across. minmax(0,1fr) again: at two columns the tracks are wider, but
     the minmax(0) is what stops a long project name from setting the floor
     and overflowing the row. */
  .trz-shot-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}

@media (max-width:680px){
  .trz-shots,.trz-swatches{padding-top:1.75rem;margin-top:2rem}

  /* One across. A photograph of a building needs enough width to read as a
     building; two at 340px each on a phone is two pictures of nothing. */
  .trz-shot-grid{grid-template-columns:minmax(0,1fr);gap:1.5rem}

  /* On a phone nine 4:5 tiles across 375px would be 29px each, which is a
     postage stamp with a colour code under it. The row becomes two rows of
     four and a fifth line of one: flex-basis is set so the browser wraps it
     at four, and the last tile is allowed to sit alone rather than being
     stretched to fill, which is what flex:1 does when there is one item on
     the line. So the basis is declared and grow is switched off below 680px
     — the one place in this block where a number beats flex:1. */
  .trz-swatch{flex:0 0 calc((100% - 2.7rem) / 4)}

  .trz-shots-note{font-size:.875rem}
}

/* ⛔ NO CONTENT IMAGERY GETS A max-width RULE HERE.
   Every image in this block is width:100% inside a track that is itself
   minmax(0,1fr), and the global img{max-width:100%} in this stylesheet
   already covers the case where the track cannot hold it. Adding another
   max-width to a new rule is how a 1024px-wide picture ends up on a
   375px phone while the gate that checks for it passes on the desktop
   viewport it was written for. */

/* ==========================================================================
   THE BANNER — one photograph, above the questions
   ==========================================================================
   The band answered "are there pictures on this site". It did not answer
   "why am I looking at text when I arrived", because the band was 1.21
   screens down. This is the picture that is in the first screen.

   ⛔ IT IS AN <a>, NOT A <figure>, SO THE PHOTOGRAPH IS A LINK AND NOT
   DECORATION. A figure with no link would be the failure mode the whole
   block exists to avoid: a picture that leads nowhere and earns nothing.

   ⛔ AND THE CAPTION SITS UNDER THE PICTURE, NOT OVER IT.
   Terrazzo is a light material and these photographs are interiors with
   windows in them; a caption in a dark scrim over one of those is a caption
   whose contrast depends on which photograph happened to be there. Under it,
   on the paper, there is one number: --trz-ink on --trz-paper.
   ========================================================================== */
.trz-banner{
  display:block;
  margin:1.75rem 0 2.25rem;
  color:var(--trz-ink);
}

.trz-banner-fig{
  display:block;
  overflow:hidden;
  border-radius:12px;
  background:var(--trz-paper-3);
  /* ⛔ 840px wide by ~300px is 2.8:1, which is what the slot measures on
     this station's reading column. The banner size is tmq-large at 1280x720
     (1.78:1), so object-fit has to crop, and the crop is a letterbox
     through the middle of the frame. A floor seen from above loses its
     subject in that crop; a facade or a concourse does not, which is why the
     banner photograph was chosen on its aspect ratio rather than on how good
     it looked in a grid. */
  aspect-ratio:28/10;
}
.trz-banner-img{
  width:100%;
  height:100%;
  object-fit:cover;
  /* Where object-position is default (centre), a letterbox cuts equally top
     and bottom. Terrazzo installations in these photographs put the floor
     and the wall junction near the middle, so centre is right here and a
     top-aligned crop would have shown ceiling. Stated because the next
     person to change this will assume it needs adjusting. */
  object-position:center;
  display:block;
}
.trz-banner:hover .trz-banner-img{opacity:.93}

.trz-banner-cap{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:1rem;
  flex-wrap:wrap;
  padding-top:.65rem;
}
.trz-banner-t{
  font-size:1rem;
  line-height:1.36;
  font-weight:590;
  letter-spacing:-.011em;
  color:var(--trz-ink);
}
.trz-banner-go{
  font-size:.8125rem;
  line-height:1.4;
  color:var(--trz-red);
  white-space:nowrap;
}
.trz-banner:hover .trz-banner-t{color:var(--trz-red)}

.trz-banner:focus-visible{
  outline:2px solid var(--trz-red);
  outline-offset:4px;
  border-radius:12px;
}

@media (max-width:680px){
  .trz-banner{margin:1.35rem 0 1.75rem}
  /* 16:10 on a phone rather than 28:10. A 375px-wide 2.8:1 letterbox is
     134px tall, which is a slot you can see past before you have read it.
     The photograph is the same one and the link is the same one; only the
     frame gets taller so the picture can actually register on a small
     screen. */
  .trz-banner-fig{aspect-ratio:16/10}
  .trz-banner-cap{gap:.35rem}
}

/* ==========================================================================
   THE PHOTOGRAPH ON AN INNER PAGE
   ==========================================================================
   BOSS, 2026-10-22: "我们很多页面都是密密麻麻的文字." Six inner pages carried
   no picture at all, and /about/ carried one unbroken paragraph of 723
   characters.

   The photograph goes after the lede, at the full width of the reading
   column, because on a page that is mostly text the picture is what breaks
   the run of paragraphs. Making it small, or putting it beside the text,
   would leave the wall intact.

   ⛔ IT IS AN <a>. Same rule as every other photograph on this station: a
   picture that goes nowhere is decoration, and decoration earns no internal
   link and no reason for a reader to keep looking.

   ⛔ THE CAPTION IS BELOW THE PICTURE, ON THE PAPER, IN INK.
   One ground, one number, one verdict — --trz-ink on --trz-paper. The same
   rule that killed the crimson that sat 0.04 under the floor.
   ========================================================================== */
.trz-page-photo{
  margin:2rem 0 2.25rem;
}

.trz-page-photo-link{
  display:block;
  overflow:hidden;
  border-radius:12px;
  background:var(--trz-paper-3);
  /* 16:9. The reading column is 840px, so this is 840x472. A taller crop
   * would push the next paragraph below the fold, and the point of the
   * photograph is to interrupt the text, not to end the page. */
  aspect-ratio:16/9;
}
.trz-page-photo-img{
  width:100%;
  height:100%;
  object-fit:cover;
  display:block;
}
.trz-page-photo-link:hover .trz-page-photo-img{opacity:.93}

.trz-page-photo-cap{
  margin:.6rem 0 0;
  font-size:.875rem;
  line-height:1.5;
  color:var(--trz-ink-3);
  /* 52ch: the caption is a sentence, not a heading, and a caption that
   * runs the full width of a 840px column is a caption nobody reads to the
   * end. */
  max-width:52ch;
}

.trz-page-photo-link:focus-visible{
  outline:2px solid var(--trz-red);
  outline-offset:4px;
  border-radius:12px;
}

@media (max-width:680px){
  .trz-page-photo{margin:1.5rem 0 1.75rem}
  /* 4:3 on a phone. A 375px-wide 16:9 is 211px tall, which is a band
   * rather than a picture; 4:3 is 281px and reads as an image. */
  .trz-page-photo-link{aspect-ratio:4/3}
  .trz-page-photo-cap{font-size:.8125rem}
}


/* ==================================================================
   THE DARK CONTAINERS ON A PAPER GROUND
   ==================================================================
   ⛔ THIS BLOCK EXISTS BECAUSE THIS STATION IS A PAPER GROUND AND THE
   ONE IT WAS FORKED FROM IS NOT.

   The fourth station is a dark station: its --text is a light cream, so
   a heading inside a dark panel inherits the light colour and is
   readable without anybody thinking about it. This station is a paper
   ground: --text is near-black, which is right for the page and fatal
   for a panel.

   And the failure is quiet. The panel is a deep blue-black gradient and
   the heading on it is near-black, which measures 1.1:1 — a title a
   reader cannot read, on a band that occupies the bottom of the page.
   The contrast gate that caught the other two stations compared each
   element's text with the PAGE background rather than with the panel it
   sits in, so dark text on a dark panel computed as excellent contrast
   against the cream. The page passed every check and had an unreadable
   title on it.

   ⛔ AND THE FIRST VERSION OF THIS FIX LISTED h2 AND NOTHING ELSE.
   The panel's heading is an h3, not an h2 — the fourth station's template
   chose the level, and the rule that pinned the colour was written for
   the level that station happened to use. So the rule matched nothing
   here and the heading inherited the page's near-black.

   ⛔ SO THE COLOUR IS PINNED FOR EVERY HEADING LEVEL, AND THE PANEL
   REDECLARES THE VARIABLES IT CONTAINS. The re-declaration is the part
   that stops the next omission: anything inside the panel that asks for
   var(--text) or var(--muted) gets the panel's own value, and a panel on
   a paper ground stops depending on what the page happens to use.

   The three stations that share the theme carry the same block without
   the body.trz prefix, because their body has no trz class. This
   station's body does, so the prefix is here — and the prefix is the
   reason the rule cannot leak onto another station.
   ================================================================== */
body.trz .cta-band{
  --text:#F4F2ED;
  --text-soft:#E4E1D9;
  --muted:#BFB8A9;
  --gold-soft:#E8D9AE;
}
body.trz .cta-band h1,
body.trz .cta-band h2,
body.trz .cta-band h3,
body.trz .cta-band h4{color:#F4F2ED}
body.trz .cta-band p,
body.trz .cta-band li{color:#E4E1D9}
body.trz .cta-band .sub,
body.trz .cta-band .muted,
body.trz .cta-band .meta{color:#BFB8A9}
body.trz .cta-band a:not(.btn):not(.btn-gold){color:#E8D9AE}

/* The badges that sit ON a photograph keep their own dark ground, and
   their own light text — the page ground has nothing to do with them. */
body.trz .verified-badge{background:rgba(11,11,13,.82);color:#E8D9AE}
body.trz .dl-badge{background:rgba(14,14,12,.82);color:#E8D9AE;border-color:rgba(201,168,106,.4)}
body.trz .dl-badge.is-member{color:#E8D9AE}

/* The hero, when it carries a photograph, is a panel too. */
body.trz .hero h1{color:#F4F2ED}
body.trz .hero p.lead{color:#E4E1D9}
body.trz .hero .eyebrow{color:#E8D9AE}

/* ==========================================================================
   THE APPLICATION CARDS ON A FORM PAGE
   ==========================================================================
   Twelve rooms are mounted onto the forms they illustrate
   (seed/coffeewood_case_mounts.php writes them as `tmq_case_cards`, and
   taxonomy-form.php is the only place that reads them).

   ⛔ THE GRID USES minmax(0,1fr), NOT 1fr.
   A grid item's default min-width is auto, so an item refuses to be
   narrower than its own content — and the card's longest word is a
   caption. With `1fr` and a long caption, the track is pushed past the
   column and the phone viewport is widened by the browser, which is the
   exact fault this project has now paid for three times. The card itself
   carries min-width:0 for the same reason.

   ⛔ THE "Render" TAG IS ON EVERY CARD, ALWAYS.
   These are design renders, not photographs of installed work. The
   article says so, the caption says so, and the card says so — because
   the card is the version a buyer sees on the page they landed on, and
   the version they landed on has to carry the fact too.

   ⛔ AND THE RULE IS IN THIS STATION'S STYLESHEET, NOT THE SHARED THEME.
   The other three stations have no application cards and must not grow
   an unused rule; this station's file is its own.
   ========================================================================== */
.cw-case-grid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(0,1fr));
  gap:1.1rem;
  margin:0 0 8px;
}
.cw-case-card{
  min-width:0;
  display:flex;
  flex-direction:column;
  border:1px solid var(--rule,rgba(20,17,13,.12));
  border-radius:10px;
  overflow:hidden;
  background:#fff;
  text-decoration:none;
  color:inherit;
  transition:border-color .15s ease;
}
.cw-case-card:hover{border-color:rgba(201,168,106,.55)}
.cw-case-fig{
  position:relative;
  display:block;
  aspect-ratio:3/2;
  overflow:hidden;
  background:#F1EEE8;
}
.cw-case-img{
  width:100%;
  height:100%;
  object-fit:cover;
  display:block;
}
.cw-case-nophoto{display:block;width:100%;height:100%}
/* ⛔ THE TAG SITS ON ITS OWN PLATE, NOT ON THE PICTURE.
   The picture underneath is a pale render — a bathroom is white and a
   corridor is cream — so a translucent dark tag over it would be
   unreadable on half the set. The plate is opaque instead. */
.cw-case-tag{
  position:absolute;
  left:8px;
  top:8px;
  z-index:1;
  display:inline-block;
  padding:2px 7px;
  border-radius:999px;
  background:rgba(22,19,15,.86);
  color:#F6F4EF;
  font-size:10.5px;
  font-weight:600;
  letter-spacing:.04em;
  text-transform:uppercase;
  line-height:1.5;
}
.cw-case-body{
  min-width:0;
  padding:.7rem .8rem .8rem;
  display:flex;
  flex-direction:column;
  gap:.3rem;
}
.cw-case-t{
  font-size:.9375rem;
  font-weight:600;
  line-height:1.3;
  color:var(--text,#16130F);
}
.cw-case-scene{
  font-size:.8125rem;
  line-height:1.5;
  color:var(--muted,#5F5E5A);
  /* ⛔ AND THE CAPTION IS CLAMPED TO THREE LINES.
     The scene descriptions are two or three sentences. A card is not
     the place to read them, and a card that grows to fit a paragraph
     makes the row it sits in taller than its neighbours. */
  display:-webkit-box;
  -webkit-line-clamp:3;
  line-clamp:3;
  -webkit-box-orient:vertical;
  overflow:hidden;
}
@media (max-width:680px){
  .cw-case-grid{grid-template-columns:minmax(0,1fr);gap:.9rem}
  .cw-case-scene{-webkit-line-clamp:2;line-clamp:2}
}
