/* ============================================================
   chrisscott.me — Rebuilding the Wall
   The construction document. See index.html for the contract.
   ============================================================ */

/* ---------- 1. Tokens ---------- */
:root{
  /* Sampled from the approved print files */
  --wall-blue:#2550A8;
  --hero-blue:#2650AC;          /* matches the hero plate's own field */
  --ink:#0D0D0F;
  --paper:#FFFFFF;
  --signal:#3B7BFF;
  --bone:#F4F5F7;

  --blue-900:#0D1C3B;
  --blue-800:#122854;
  --blue-700:#18346D;
  --blue-600:#1D4086;   /* body-size links on white: 9.86:1 */
  --blue-400:#366AD3;
  --blue-300:#7195E0;   /* body-size text on ink: 6.54:1 */
  --blue-200:#ABC1ED;
  --blue-100:#D5E0F6;
  --blue-050:#EEF3FB;

  /* Drafting layer */
  /* Rules are structure here, not decoration, so they are drawn to be seen.
     Raised from .16/.34/.22/.30 — at the old weights they read as artifacts. */
  --rule:rgba(13,13,15,.34);
  --rule-strong:rgba(13,13,15,.46);
  --rule-on-dark:rgba(255,255,255,.34);
  --rule-on-blue:rgba(255,255,255,.42);

  /* Label colours. The old alpha values measured 2.24:1 and 3.94:1 and failed
     outright. These are solid and measured: 7.04:1 on white, 5.42:1 on blue. */
  --label-on-paper:#55555D;
  --label-on-blue:rgba(255,255,255,.84);
  --label-on-ink:rgba(255,255,255,.72);

  --sq:4px;  --sh:12px;                 /* micro steps: tick gaps, row padding */
  --s1:8px;  --s2:16px; --s3:24px; --s4:32px;
  --s5:48px; --s6:64px; --s7:96px; --s8:128px;

  --measure:66ch;
  --pad:24px;
  --maxw:1240px;
  --titleblock-h:60px;

  --ease:cubic-bezier(.2,.7,.3,1);
}
@media (min-width:768px){ :root{ --pad:40px } }
@media (min-width:1200px){ :root{ --pad:64px } }

/* ---------- 2. Faces ---------- */
@font-face{font-family:Montserrat;src:url(fonts/Montserrat.woff2)format('woff2');
  font-weight:100 900;font-style:normal;font-display:swap}
/* Public Sans: the face of US federal specification documents. It belongs to
   this page's world, and it disappears cleanly under Montserrat Black. */
@font-face{font-family:'Public Sans';src:url(fonts/PublicSans.woff2)format('woff2');
  font-weight:100 900;font-style:normal;font-display:swap}
@font-face{font-family:'Azeret Mono';src:url(fonts/AzeretMono.woff2)format('woff2');
  font-weight:100 900;font-style:normal;font-display:swap}

/* ---------- 3. Reset ---------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;overflow-x:clip}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font:400 17px/1.65 'Public Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,sans-serif;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,svg{display:block;max-width:100%}
/* The browser's default figure margin is 1em 40px, which pushed sheet 03's
   book shot 40px off the grid's left edge while every other sheet sat at it. */
figure{margin:0}
button{font:inherit;color:inherit}
a{color:var(--blue-600);text-underline-offset:3px;text-decoration-thickness:1px}
:focus-visible{outline:3px solid var(--blue-400);outline-offset:3px;border-radius:2px}
.on-blue :focus-visible,.on-ink :focus-visible{outline-color:#fff}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------- 4. Type ---------- */
h1,h2,h3{font-family:Montserrat,"Helvetica Neue",Arial,sans-serif;font-weight:900;
  text-transform:uppercase;margin:0;text-wrap:balance;letter-spacing:-.02em}
h1{font-size:clamp(2.5rem,9.4vw,6rem);line-height:.92}
h2{font-size:clamp(2rem,6.2vw,4rem);line-height:.95}
h3{font-size:clamp(1.5rem,3.4vw,2.5rem);line-height:1;letter-spacing:-.01em}
p{margin:0 0 var(--s3);max-width:var(--measure)}
.lead{font-size:clamp(1.15rem,2.1vw,1.375rem);line-height:1.5}
.small{font-size:1rem;line-height:1.6}

/* The annotation layer. Mono is reserved for measurement, identifiers and data.
   Sized for older eyes: 11px uppercase mono was the least readable thing on the
   page. Up to 13/14px, and a heavier weight so the thin strokes survive. */
.anno{font-family:'Azeret Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:.8125rem;font-weight:500;letter-spacing:.1em;text-transform:uppercase;
  line-height:1.5;font-variant-numeric:tabular-nums}
@media (min-width:768px){.anno{font-size:.875rem}}

/* ---------- 5. Sheets ---------- */
.sheet{position:relative;padding:var(--s7) 0;scroll-margin-top:64px}
@media (min-width:768px){.sheet{padding:var(--s8) 0}}
.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--pad)}

.on-ink{background:var(--ink);color:#fff}
.on-ink p{color:var(--blue-200)}
.on-ink a,.titleblock a{color:#fff}
.on-blue a{color:#fff}
.on-blue{background:var(--wall-blue);color:#fff}
.on-blue p{color:rgba(255,255,255,.92)}
.on-bone{background:var(--bone)}

/* The drawing-set margin rail: sheet identity lives here, never as a kicker
   sitting on top of a heading. */
.rail{display:none}
@media (min-width:1100px){
  .rail{display:block;position:absolute;left:16px;top:var(--s7);bottom:var(--s7);width:34px}
  .rail::before{content:"";position:absolute;left:22px;top:0;bottom:0;width:1px;background:var(--rule)}
  .on-ink .rail::before,.on-blue .rail::before{background:var(--rule-on-dark)}
  .rail-id{position:absolute;top:0;left:14px;transform-origin:0 0;transform:rotate(90deg);
    white-space:nowrap;padding-left:18px;color:var(--label-on-paper)}
  .on-ink .rail-id{color:var(--label-on-ink)}
  .on-blue .rail-id{color:var(--label-on-blue)}
  .rail-tick{position:absolute;left:16px;width:13px;height:1px;background:var(--rule)}
  .on-ink .rail-tick,.on-blue .rail-tick{background:var(--rule-on-dark)}
}

/* ---------- 6. Drafting primitives ---------- */
/* A dimension line: a rule with tick ends, the way a drawing measures a thing. */
.dim{position:relative;height:1px;background:var(--rule-strong);
  transform-origin:left center}
.dim::before,.dim::after{content:"";position:absolute;top:-4px;width:1px;height:9px;
  background:var(--rule-strong)}
.dim::before{left:0}.dim::after{right:0}
.on-ink .dim,.on-blue .dim{background:var(--rule-on-blue)}
.on-ink .dim::before,.on-ink .dim::after,
.on-blue .dim::before,.on-blue .dim::after{background:var(--rule-on-blue)}

/* Leader-dot spec rows: label ....... value */
.spec{list-style:none;margin:0;padding:0;max-width:560px}
.spec li{display:flex;align-items:baseline;gap:var(--sh);padding:var(--sh) 0;
  border-bottom:1px solid var(--rule)}
.on-ink .spec li,.on-blue .spec li{border-bottom-color:var(--rule-on-dark)}
.spec dt,.spec .k{flex:none;color:var(--label-on-paper)}
.on-ink .spec .k{color:var(--label-on-ink)}
.on-blue .spec .k{color:var(--label-on-blue)}
.spec .dots{flex:1;height:1px;border-bottom:1px dotted var(--rule-strong);
  transform:translateY(-4px)}
.on-ink .spec .dots,.on-blue .spec .dots{border-bottom-color:rgba(255,255,255,.4)}
.spec .v{flex:0 1 auto;min-width:0;text-align:right;font-weight:600;
  font-family:'Public Sans',Helvetica,sans-serif;font-size:1.0625rem;letter-spacing:0;text-transform:none}
@media (max-width:639px){
  .spec li{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--s2);
    align-items:baseline;padding:var(--sh) 0}
  .spec .dots{display:none}
  .spec .v{text-align:right}
}
.on-ink .spec .v,.on-blue .spec .v{color:#fff}


/* ---------- 6b. THE GRID ----------
   One twelve-column field, and every sheet places its content on it. Sections
   used to invent their own proportions, which is why sheet 07 ended up a 538px
   island floating in the middle of a 1112px page while its neighbours ran full
   width. Nothing below sets its own max-width; it spans columns instead. */
.grid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));
  column-gap:var(--s5);row-gap:var(--s6)}
@media (max-width:899px){
  .grid{grid-template-columns:minmax(0,1fr);row-gap:var(--s5)}
  .grid > *{grid-column:1 / -1 !important}
}
@media (min-width:900px){
  /* Explicit ranges, not span + a separate start class. `grid-column:span 6`
     followed by `grid-column-start:7` leaves the end at auto, which silently
     collapses the element to ONE column. */
  .c4{grid-column:span 4}   .c5{grid-column:span 5}
  .c6{grid-column:span 6}   .c7{grid-column:span 7}
  .c8{grid-column:span 8}   .c9{grid-column:span 9}
  .c12{grid-column:1 / -1}
  .c6-12{grid-column:6 / -1}   .c7-12{grid-column:7 / -1}
  .c8-12{grid-column:8 / -1}
}

/* ---------- 7. Buttons ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--sh);
  min-height:54px;padding:0 28px;border:2px solid transparent;border-radius:3px;
  font:700 .9375rem/1 'Public Sans',Helvetica,sans-serif;letter-spacing:.06em;text-transform:uppercase;
  text-decoration:none;cursor:pointer;transition:background .16s var(--ease),
  color .16s var(--ease),border-color .16s var(--ease),transform .16s var(--ease)}
.btn:active{transform:translateY(1px)}
.btn-primary{background:var(--wall-blue);color:#fff;border-color:var(--wall-blue)}
.btn-primary:hover{background:var(--blue-700);border-color:var(--blue-700)}
.btn-secondary{background:transparent;color:var(--wall-blue);border-color:var(--wall-blue)}
.btn-secondary:hover{background:var(--wall-blue);color:#fff}
.on-blue .btn-primary,.on-ink .btn-primary{background:#fff;color:var(--ink);border-color:#fff}
.on-blue .btn-primary:hover,.on-ink .btn-primary:hover{background:var(--blue-100);border-color:var(--blue-100)}
.on-blue .btn-secondary,.on-ink .btn-secondary{color:#fff;border-color:rgba(255,255,255,.6)}
.on-blue .btn-secondary:hover,.on-ink .btn-secondary:hover{background:#fff;color:var(--ink);border-color:#fff}
.btn[disabled]{opacity:.55;cursor:not-allowed;transform:none}
.btn-row{display:flex;flex-wrap:wrap;gap:var(--sh);margin-top:var(--s4)}
@media (max-width:539px){.btn-row .btn{width:100%}}

/* ---------- 8. Header ---------- */
.masthead{position:sticky;top:0;z-index:60;display:flex;align-items:center;
  justify-content:space-between;gap:var(--s3);height:64px;padding-inline:var(--pad);
  background:transparent;transition:background .25s var(--ease),box-shadow .25s var(--ease)}
.masthead.stuck{background:rgba(255,255,255,.94);backdrop-filter:blur(10px);
  box-shadow:0 1px 0 var(--rule)}
.brandmark{display:flex;align-items:center;gap:var(--sh);text-decoration:none;color:inherit;
  padding-block:10px;min-height:44px}
/* The approved mark, carried as an alpha mask so it takes the surface's colour.
   The traced SVG in 03_Assets is missing glyphs and the brick stack, so the clean
   4K raster is the source of truth. */
.mark{display:block;background-color:currentColor;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-position:center;mask-position:center}
.mark-wordmark{width:116px;height:24px;
  -webkit-mask-image:url(img/logo-wordmark.png);mask-image:url(img/logo-wordmark.png)}
.mark-lockup{width:150px;height:64px;
  -webkit-mask-image:url(img/logo-lockup.png);mask-image:url(img/logo-lockup.png)}
.brandmark{color:#fff;transition:color .25s var(--ease)}
.masthead.stuck .brandmark{color:var(--ink)}
.masthead nav{display:none;gap:var(--s4)}
@media (min-width:900px){.masthead nav{display:flex}}
.masthead nav a{color:rgba(255,255,255,.85);text-decoration:none;
  font:600 .875rem/1 'Public Sans',Helvetica,sans-serif;letter-spacing:.04em;text-transform:uppercase;
  padding:var(--s1) 0;border-bottom:1px solid transparent;transition:color .2s,border-color .2s}
.masthead nav a:hover{color:#fff;border-bottom-color:#fff}
.masthead.stuck nav a{color:var(--ink)}
.masthead.stuck nav a:hover{border-bottom-color:var(--ink)}

/* ---------- 8b. The drawing index (phone + tablet navigation) ---------- */
.sheetbtn{display:flex;align-items:center;gap:var(--s1);background:none;border:0;
  padding:var(--sh) 0;min-height:44px;
  cursor:pointer;color:#fff;font:700 .8125rem/1 'Public Sans',Helvetica,sans-serif;
  letter-spacing:.08em;text-transform:uppercase;transition:color .25s var(--ease)}
.sheetbtn svg{width:20px;height:14px;fill:currentColor}
.masthead.stuck .sheetbtn{color:var(--ink)}
@media (min-width:900px){.sheetbtn{display:none}}

.sheetindex{position:fixed;inset:0;z-index:90;background:var(--ink);color:#fff;
  display:flex;flex-direction:column;padding:var(--pad);overflow-y:auto}
/* Gated like every other hidden state: if motion is off the panel is simply
   opaque the moment it is shown, never a see-through overlay. */
.motion .sheetindex{opacity:0;transition:opacity .2s var(--ease)}
.motion .sheetindex.open{opacity:1}
.sheetindex[hidden]{display:none}
.sheetindex-head{display:flex;align-items:center;justify-content:space-between;
  padding-bottom:var(--s3);border-bottom:1px solid var(--rule-on-dark);
  color:rgba(255,255,255,.55)}
.sheetclose{background:none;border:0;padding:10px;margin:-10px;cursor:pointer;color:#fff}
.sheetclose svg{width:18px;height:18px;fill:currentColor}
.sheetindex-list{display:block;padding-block:var(--s2)}
.sheetindex-list a{display:grid;grid-template-columns:46px 1fr;align-items:baseline;gap:var(--s2);
  padding:var(--s2) 0;border-bottom:1px solid var(--rule-on-dark);text-decoration:none;color:#fff}
.sheetindex-list a:last-child{border-bottom:0}
.sheetindex-list .n{font-family:'Azeret Mono',ui-monospace,monospace;font-size:.6875rem;
  font-weight:700;letter-spacing:.1em;font-variant-numeric:tabular-nums;color:var(--signal)}
.sheetindex-list .t{font-family:Montserrat,sans-serif;font-weight:900;text-transform:uppercase;
  font-size:1.25rem;letter-spacing:-.01em;line-height:1.05}
.sheetindex-list a[aria-current=true] .t{color:var(--signal)}
.sheetindex-foot{margin-top:auto;padding-top:var(--s4);display:grid;gap:var(--sh)}
.sheetindex-foot .btn{width:100%}
body.index-open{overflow:hidden}

/* ---------- 8b. Surface texture ----------
   A faint brick tooth, on three sheets only, so it stays an accent and not
   wallpaper. The tile is a NEUTRAL GRAYSCALE relief map with no colour of its
   own, healed to tile seamlessly, so it takes whatever colour it sits on.

   Strength is diluted by a flat colour layer above it rather than by opacity,
   because opacity cannot be set on a background image. --tex-veil is that
   layer: the higher it is, the fainter the brick. It is deliberately high.

   It is applied ONLY to sheets with little or no body copy. Texture behind
   reading text lowers effective contrast, and this audience cannot afford it. */
.tex{
  background-image:
    linear-gradient(var(--tex-veil),var(--tex-veil)),
    url(img/tex-brick.webp);
  background-repeat:no-repeat,repeat;
  background-size:cover,300px 300px;
  background-blend-mode:normal,soft-light;
}
.tex.on-blue{--tex-veil:rgba(37,80,168,.78)}
.cover.tex{background-image:none}  /* the cover uses .cover-wall instead */
.tex.on-ink {--tex-veil:rgba(13,13,15,.80)}
/* Measured: at these strengths white text on blue holds 7.27:1 (flat blue is
   7.52:1) and on ink 19.24:1. The texture costs almost nothing.
   The cover's wall is stronger (.85) and still measures 6.37:1 for white and
   5.03:1 for the credential labels, both clear of AA. */
@media (min-width:768px){.tex{background-size:cover,360px 360px}}

/* A brick field standing behind him: full strength at the ground line, gone by
   two thirds up. It sits UNDER the figure and under the copy (z-index 0), and
   it is masked rather than faded with opacity so the bricks themselves
   disappear instead of turning grey. */
.cover-wall{position:absolute;left:0;right:0;bottom:0;height:78%;z-index:0;
  pointer-events:none;
  background-image:url(img/tex-brick.webp);
  background-repeat:repeat;
  background-size:340px 340px;
  mix-blend-mode:soft-light;opacity:.85;
  -webkit-mask-image:linear-gradient(to top,#000 0%,rgba(0,0,0,.72) 34%,transparent 92%);
          mask-image:linear-gradient(to top,#000 0%,rgba(0,0,0,.72) 34%,transparent 92%);
}
@media (min-width:768px){.cover-wall{background-size:420px 420px}}
@media (min-width:1400px){.cover-wall{background-size:500px 500px}}
@media (prefers-reduced-motion:no-preference){
  .motion .cover-wall{opacity:0;transition:opacity 1.1s var(--ease) .15s}
  .motion .cover.is-in .cover-wall{opacity:.85}
}

/* ---------- 9. SHEET 00 — cover ----------
   Chris is bottom-anchored and stands on a ground line, the same primitive the
   wall elevations use. The plate's field is colour-matched to the section, so
   he sits IN the field rather than in a rectangle on top of it.
   Reading order differs by device on purpose: on a phone the promise is followed
   immediately by his face, because that is the hook; the credentials come after.
   On desktop the credentials sit under the headline and he holds the right. */
.cover{background:var(--hero-blue);color:#fff;position:relative;overflow:hidden;
  margin-top:-64px;padding-top:calc(64px + var(--s5));padding-bottom:0}
.cover-grid{display:grid;gap:var(--s4);align-items:end;
  grid-template-areas:"head" "fig" "meta"}
.cover-head{grid-area:head;position:relative;z-index:2}
.cover-figure{grid-area:fig}
.cover-meta{grid-area:meta;position:relative;z-index:2}

.cover-ground{position:absolute;left:0;right:0;bottom:0;height:1px;
  background:var(--rule-on-blue);pointer-events:none;z-index:2}
.cover-ground::before,.cover-ground::after{content:"";position:absolute;bottom:-5px;
  width:1px;height:11px;background:var(--rule-on-blue)}
.cover-ground::before{left:var(--pad)}
.cover-ground::after{right:var(--pad)}
.cover-datum{position:absolute;right:var(--pad);bottom:var(--s3);
  color:var(--label-on-blue);pointer-events:none;z-index:2}

.cover h1{margin-bottom:var(--s3)}
.cover .lead{max-width:24ch;color:rgba(255,255,255,.94);margin:0}
.cover .dim{margin-bottom:12px}
.cover .spec li{padding:var(--s1) 0}
.cover .btn-row{margin-top:var(--s4)}

/* He is a cut-out PNG, so there is no plate edge to hide: no masks, no colour
   matching, no feathering. He simply stands on the ground line. */
.cover-figure{position:relative;z-index:1;margin:0;align-self:end;width:100%}
.cover-figure img{display:block;width:100%;height:100%;
  object-fit:contain;object-position:bottom center}

@media (min-width:900px){
  /* Cap the hero. It used to be min-height:100svh with px-capped children, so a
     27" display stretched the section to ~1400px and left the top third empty
     while the content stayed the same size. Now it fills a 13" screen and stops
     growing past what the content can actually fill. On a tall monitor the next
     sheet peeks in, which is the right invitation anyway. */
  .cover{padding-top:calc(64px + var(--s4));
    min-height:min(100svh,900px);max-height:none;
    display:flex;align-items:flex-end}
  .cover-grid{width:100%;gap:0 var(--s6);
    grid-template-columns:minmax(0,1.05fr) minmax(0,.9fr);
    grid-template-areas:"head fig" "meta fig"}
  .cover h1{font-size:clamp(3rem,6.4vw,6rem)}
  .cover-head{padding-bottom:var(--s4)}
  .cover-meta{padding-bottom:var(--s7)}
  .cover-figure{height:min(72svh,720px);padding-bottom:0}
}

/* Phone and tablet: he stands on his own datum, mid-stack. */
@media (max-width:899px){
  .cover{padding-top:calc(64px + var(--s4))}
  .cover-grid{gap:var(--s3)}
  .cover-figure{height:min(48svh,430px);padding-bottom:0}
  .cover-figure img{object-position:bottom center}
  /* The datum travels with him. */
  .cover-figure::after{content:"";position:absolute;bottom:0;height:1px;
    left:calc(var(--pad)*-1);right:calc(var(--pad)*-1);
    background:var(--rule-on-blue)}
  .cover-meta{padding-bottom:var(--s6)}
  .cover-ground{display:none}
  .cover-datum{bottom:20px;right:var(--pad)}
}
@media (min-width:600px) and (max-width:899px){
  .cover-grid{gap:var(--s2)}
  .cover-figure{height:min(52svh,540px)}
}

/* ---------- 10. SHEET 01 — existing conditions ---------- */
.survey{max-width:22ch}
@media (max-width:699px){.survey{max-width:none}}
.survey-line{display:block;font-family:Montserrat,sans-serif;font-weight:900;
  text-transform:uppercase;font-size:clamp(1.05rem,3vw,1.75rem);line-height:1.25;
  color:rgba(255,255,255,.55)}
@media (min-width:700px){.survey-line{white-space:nowrap}}
.verdict{margin:var(--s4) 0 var(--s2)}
.verdict-call{font-family:Montserrat,sans-serif;font-weight:900;text-transform:uppercase;
  font-size:clamp(1.05rem,2.6vw,1.5rem);letter-spacing:-.01em;color:var(--signal);
  margin:0 0 var(--s5)}
.condition-note{max-width:52ch;color:var(--blue-200)}

/* ---------- 11. SHEET 02 — the four walls ---------- */
.walls{display:grid;gap:var(--s6);margin-top:var(--s6)}
@media (min-width:760px){.walls{grid-template-columns:1fr 1fr;gap:var(--s6) var(--s5)}}
.wall{display:grid;gap:var(--s3)}
.wall-head{display:flex;align-items:baseline;gap:var(--sh)}
.wall-num{font-family:Montserrat,sans-serif;font-weight:900;font-size:2rem;line-height:.8;
  color:var(--wall-blue);flex:none;font-variant-numeric:tabular-nums}
.wall h3{font-size:clamp(1.125rem,2.4vw,1.5rem)}
.wall p{margin:0;font-size:1rem;color:#3a3a40;max-width:36ch}
.elevation{width:100%;height:auto;display:block}
.ground{fill:var(--ink);opacity:.75}
.dimline{fill:var(--rule-strong)}
.brick{fill:var(--wall-blue)}
.brick-gap{fill:var(--blue-050);stroke:var(--rule-strong);stroke-width:1;stroke-dasharray:3 3}
.brick-fill{fill:var(--signal)}

/* Inspecting a wall.
   A drawing set does not pop a card up on hover; it puts one elevation under
   the lamp and lets the rest of the sheet fall back. So the wall you are on
   holds full strength and its number strikes signal blue, while its siblings
   recede. No lift, no shadow, no scale: this world has none of those.

   The same state is driven by touch, so a phone is not a lesser experience:
   `.is-focus` is set on whichever wall is nearest the centre of the screen. */
.wall .brick,.wall .brick-fill,.wall .brick-gap,.wall .wall-num,.wall h3,.wall p{
  transition:fill .35s var(--ease),color .35s var(--ease),opacity .35s var(--ease)}
.wall svg{transition:opacity .35s var(--ease)}

.wall.is-dim svg,.wall.is-dim .wall-head,.wall.is-dim p{opacity:.42}
.wall.is-focus .wall-num{color:var(--signal)}
.wall.is-focus .brick-fill{fill:var(--signal)}
.wall.is-focus .brick-gap{stroke:var(--signal);stroke-dasharray:none}
.wall.is-focus .dimline{fill:var(--signal)}

@media (hover:hover) and (pointer:fine){
  .walls:hover .wall:not(:hover) svg,
  .walls:hover .wall:not(:hover) .wall-head,
  .walls:hover .wall:not(:hover) p{opacity:.42}
  .walls .wall:hover .wall-num{color:var(--signal)}
  .walls .wall:hover .brick-gap{stroke:var(--signal);stroke-dasharray:none}
  .walls .wall:hover .dimline{fill:var(--signal)}
}

@media (prefers-reduced-motion:reduce){
  .wall .brick,.wall .brick-fill,.wall .brick-gap,.wall .wall-num,
  .wall h3,.wall p,.wall svg{transition:none}
}

/* ---------- 12. SHEET 03 — specification ---------- */
.specsheet{display:grid;gap:var(--s6);align-items:start}
@media (min-width:900px){
  .specsheet{grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--s5)}
  .specsheet > figure{grid-column:span 4}
  .specsheet > div{grid-column:6 / -1}
}
.bookshot{position:relative}
.bookshot img{width:100%;height:auto;border:1px solid var(--rule)}
.bookshot .dim{margin-top:14px}
.buy-note{margin-top:var(--s3);color:var(--blue-600);max-width:46ch}
.gift-note{margin-top:var(--s2);color:#55555c;max-width:46ch}

/* ---------- 13. SHEET 04 — the builder ---------- */
.builder{display:grid;gap:var(--s6);align-items:start}
.builder h2{max-width:13ch}
@media (min-width:900px){
  .builder{grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--s5)}
  .builder > figure{grid-column:span 4}
  .builder > div{grid-column:6 / -1}
}
.builder figure{margin:0}
.builder img{width:100%;height:auto;border-radius:6px;filter:saturate(.96)}
.log{list-style:none;margin:var(--s5) 0 0;padding:0;max-width:600px}
.log li{display:grid;grid-template-columns:72px 1fr;gap:var(--s3);
  padding:var(--s2) 0;border-top:1px solid var(--rule)}
.log li:last-child{border-bottom:1px solid var(--rule)}
.log .yr{font-family:'Azeret Mono',ui-monospace,monospace;font-size:.6875rem;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;font-variant-numeric:tabular-nums;
  color:var(--wall-blue);padding-top:4px}
.log .ev{margin:0;font-family:'Public Sans',Helvetica,sans-serif;font-size:1rem;line-height:1.55;
  letter-spacing:0;text-transform:none;color:#3a3a40;max-width:46ch}
.pullquote{margin:var(--s6) 0 0;padding:0 0 0 var(--s3);border-left:1px solid var(--wall-blue);
  font-family:Montserrat,sans-serif;font-weight:800;text-transform:none;
  font-size:clamp(1.25rem,2.6vw,1.75rem);line-height:1.28;letter-spacing:-.01em;
  color:var(--wall-blue);max-width:24ch}

/* ---------- 14. SHEET 05 — scope of work ---------- */
.scope{display:grid;gap:var(--s6)}
@media (min-width:900px){
  .scope{grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--s5);
    row-gap:var(--s7);align-items:start}
  .scope > div:first-child{grid-column:span 6}
  .scope > div:last-child{grid-column:8 / -1}
}
.topics{list-style:none;margin:var(--s5) 0 0;padding:0}
.topics li{padding:var(--s3) 0;border-top:1px solid var(--rule-on-blue)}
.topics li:last-child{border-bottom:1px solid var(--rule-on-blue)}
.topics h3{font-size:clamp(1.05rem,2.2vw,1.375rem);margin-bottom:6px}
.topics p{margin:0;font-size:1rem;max-width:40ch}
/* The source is a 2:3 portrait. It used to be forced into a 5:4 landscape box,
   which cropped his chin off. The box is portrait now, so almost nothing is
   lost and the crop reads as a decision rather than an accident. */
.scope-figure img{width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;
  object-position:center 28%;border-radius:6px}
@media (min-width:900px){.scope-figure img{aspect-ratio:5/6}}

.form{display:grid;gap:var(--s3);background:rgba(13,13,15,.22);padding:var(--s4);
  border-radius:4px;border:1px solid var(--rule-on-blue)}
@media (min-width:600px){.form{padding:var(--s5)}}
.field{display:grid;gap:var(--s1)}
.field label{font:600 .8125rem/1.3 'Public Sans',Helvetica,sans-serif;letter-spacing:.04em;
  text-transform:uppercase;color:rgba(255,255,255,.9)}
.field input,.field select,.field textarea{
  width:100%;min-height:52px;padding:14px 15px;border-radius:3px;
  border:1px solid rgba(255,255,255,.42);background:rgba(255,255,255,.07);color:#fff;
  font:400 1rem/1.4 'Public Sans',Helvetica,sans-serif;transition:border-color .16s,background .16s}
.field textarea{min-height:112px;resize:vertical}
.field select{appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,#fff 50%),linear-gradient(135deg,#fff 50%,transparent 50%);
  background-position:calc(100% - 20px) 23px,calc(100% - 14px) 23px;
  background-size:6px 6px,6px 6px;background-repeat:no-repeat}
.field input::placeholder,.field textarea::placeholder{color:rgba(255,255,255,.55)}
.field input:hover,.field select:hover,.field textarea:hover{border-color:rgba(255,255,255,.7)}
.field input:focus,.field select:focus,.field textarea:focus{
  background:rgba(255,255,255,.13);border-color:#fff;outline:3px solid rgba(255,255,255,.45);outline-offset:1px}
.field-2{display:grid;gap:var(--s3)}
@media (min-width:600px){.field-2{grid-template-columns:1fr 1fr}}
.err{display:none;font:500 .8125rem/1.4 'Public Sans',Helvetica,sans-serif;color:#FFD5D5}
.field.invalid input,.field.invalid select,.field.invalid textarea{border-color:#FF9A9A}
.field.invalid .err{display:block}
.form-note{margin:0;font-size:.9375rem;color:rgba(255,255,255,.82);max-width:44ch}
.form-done{display:none;padding:var(--s5);border:1px solid rgba(255,255,255,.42);
  border-radius:4px;background:rgba(13,13,15,.22)}
.form-done h3{margin-bottom:var(--s2);font-size:1.375rem}
.form-done p{margin:0;color:rgba(255,255,255,.92)}
.is-sent .form{display:none}
.is-sent .form-done{display:block}

/* ---------- 15. SHEET 06 — field reports ----------
   Reviews are readings taken in the field, so they are set as report entries on
   a rule, not as a row of testimonial cards. The foreword leads because it is
   the most authoritative; the Amazon reviews follow as logged findings. */
.reports{display:grid;gap:var(--s6);align-items:start}
.reports h2{max-width:11ch}
.report-quote{font-family:Montserrat,sans-serif;font-weight:800;text-transform:none;
  font-size:clamp(1.5rem,4vw,2.375rem);line-height:1.2;letter-spacing:-.015em;
  margin:0 0 var(--s4);max-width:18ch}
.report-body{max-width:62ch;color:#3a3a40}
.report-by{margin-top:var(--s3);color:var(--label-on-paper)}
@media (min-width:900px){
  .reports{grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--s5)}
  .reports > div:first-child{grid-column:span 4}
  .reports > div:last-child{grid-column:6 / -1}
}

/* The logged findings. Named `reviews`, not `log`: sheet 04's site log already
   owns `.log` and caps it at 600px, which was squeezing these into 268px columns. */
.reviews{margin-top:var(--s7);border-top:2px solid var(--rule-strong);padding-top:var(--s2)}
.reviews-head{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;
  gap:var(--s2);color:var(--label-on-paper);padding-block:var(--s2)}
.reviews-list{list-style:none;margin:0;padding:0;display:grid;gap:0}
.reviews-list li{border-top:1px solid var(--rule);padding:var(--s4) 0;
  display:grid;gap:var(--s2) var(--s4)}
@media (min-width:820px){
  .reviews-list{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--s5)}
  .reviews-list li{grid-template-columns:minmax(0,1fr);align-content:start}
  .reviews-list li:nth-child(2){border-top:1px solid var(--rule)}
}
@media (min-width:1200px){.reviews-list{column-gap:var(--s6)}}
.review-who{display:grid;gap:var(--s1);align-content:start}
.review-name{font-weight:700;font-size:1.0625rem;line-height:1.35}
.review-role{color:var(--label-on-paper);font-size:.9375rem;line-height:1.45}
.review-q{margin:0;font-size:1.0625rem;line-height:1.58;max-width:52ch}
.review-q + .review-meta{margin-top:var(--s2)}
.review-meta{color:var(--label-on-paper)}

/* Rating: a test result on a drawing, not a shop badge. */
.rating{display:flex;align-items:center;gap:var(--sh);flex-wrap:wrap}
.stars{flex:none;display:block;height:22px;width:auto}
.rating-score{font-family:Montserrat,sans-serif;font-weight:900;font-size:1.5rem;
  line-height:1;letter-spacing:-.01em}
.rating-text{color:var(--label-on-paper);line-height:1.4}
.on-blue .rating-text{color:var(--label-on-blue)}
.on-ink .rating-text{color:var(--label-on-ink)}
.rating a{text-underline-offset:3px;display:inline-flex;align-items:center;
  min-height:44px;padding-block:4px}
.cover .rating{margin-top:var(--s4)}
.rating-big{gap:var(--s3)}
.rating-big .stars{height:30px}
.rating-big .rating-score{font-size:2.25rem}

/* Where to buy: formats and prices, stated plainly. Nobody should have to
   click through to find out what it costs. */
.formats{list-style:none;margin:var(--s4) 0 0;padding:0;display:grid;gap:0;max-width:560px}
.formats li{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--sh);
  padding:var(--s3) 0;border-top:1px solid var(--rule)}
.formats li:last-child{border-bottom:1px solid var(--rule)}
.fmt-name{font-weight:700;font-size:1.0625rem;flex:none;min-width:104px}
.fmt-price{font-family:Montserrat,sans-serif;font-weight:900;font-size:1.25rem;
  letter-spacing:-.01em;margin-left:auto}
.fmt-note{color:var(--label-on-paper);font-size:.9375rem;flex-basis:100%}
.fmt-was{color:var(--label-on-paper);font-weight:400;font-size:1rem;
  text-decoration:line-through;margin-left:8px}

/* ---------- 16. SHEET 07 — the umbrella ---------- */
.umbrella h2{max-width:14ch}
.umbrella .btn-row{margin-top:var(--s5)}
.umbrella p{max-width:56ch}
.legal{margin-top:var(--s5);color:var(--blue-300);font-size:.875rem;max-width:52ch}

/* ---------- 17. Final call ---------- */
.finalcall h2{max-width:22ch;margin-bottom:var(--s4)}
.signup{display:flex;flex-wrap:wrap;gap:var(--sh);margin-top:var(--s6);max-width:520px}
.signup input{flex:1 1 220px;min-height:54px;padding:14px 16px;border-radius:3px;
  border:1px solid rgba(255,255,255,.5);background:rgba(255,255,255,.09);color:#fff;
  font:400 1rem/1.4 'Public Sans',Helvetica,sans-serif}
.signup input::placeholder{color:rgba(255,255,255,.6)}
.signup input:focus{background:rgba(255,255,255,.15);border-color:#fff;
  outline:3px solid rgba(255,255,255,.45);outline-offset:1px}
.signup-note{margin-top:14px;color:rgba(255,255,255,.8);font-size:.9375rem}

/* ---------- 18. The title block (footer) ---------- */
.titleblock{background:var(--ink);color:#fff;padding:var(--s6) 0 calc(var(--s6) + var(--titleblock-h))}
.tb-grid{display:grid;gap:0;border:1px solid var(--rule-on-dark)}
@media (min-width:700px){.tb-grid{grid-template-columns:repeat(4,1fr)}}
.tb-cell{padding:16px 18px;border-bottom:1px solid var(--rule-on-dark)}
@media (min-width:700px){
  .tb-cell{border-right:1px solid var(--rule-on-dark);border-bottom:none}
  .tb-cell:last-child{border-right:none}
}
@media (max-width:699px){.tb-cell:last-child{border-bottom:none}}
.tb-k{color:rgba(255,255,255,.55);display:block;margin-bottom:7px}
.tb-v{font:600 .9375rem/1.4 'Public Sans',Helvetica,sans-serif}
.tb-foot{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s5);align-items:center;
  justify-content:space-between;margin-top:var(--s5)}
.tb-links{display:flex;flex-wrap:wrap;gap:0 var(--s3);align-items:center}
.tb-links a{color:rgba(255,255,255,.82);text-decoration:none;font-size:.9375rem;
  display:inline-flex;align-items:center;min-height:44px}
.tb-links a:hover{color:#fff;text-decoration:underline}
.tb-cell .tb-v a{display:inline-flex;align-items:center;min-height:44px}
.tb-foot .mark-lockup{color:#fff}

/* ---------- 19. The sticky title-block bar ---------- */
.tbbar{position:fixed;left:0;right:0;bottom:0;z-index:70;height:var(--titleblock-h);
  display:flex;align-items:center;gap:var(--s3);padding-inline:var(--pad);
  background:var(--ink);border-top:1px solid rgba(255,255,255,.2);
  transform:translateY(105%);transition:transform .32s var(--ease)}
.tbbar.up{transform:translateY(0)}
.tbbar-now{display:flex;align-items:center;gap:var(--sh);min-width:0;flex:1;
  color:rgba(255,255,255,.62)}
.tbbar-name{color:#fff;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tbbar-ticks{display:none;gap:var(--sq);align-items:center}
@media (min-width:900px){.tbbar-ticks{display:flex}}
.tbbar-ticks a{width:22px;height:22px;display:grid;place-items:center;border-radius:2px;
  text-decoration:none;color:rgba(255,255,255,.72);
  font:400 .8125rem/1 'Azeret Mono',monospace;font-variant-numeric:tabular-nums;
  transition:color .18s,background .18s}
.tbbar-ticks a:hover{color:#fff;background:rgba(255,255,255,.14)}
.tbbar-ticks a[aria-current=true]{color:var(--ink);background:#fff;font-weight:700}
.tbbar .btn{min-height:44px;padding:0 18px;font-size:.8125rem;flex:none}
@media (max-width:539px){.tbbar{gap:var(--sh);padding-inline:16px}.tbbar .btn{padding:0 14px}}

/* ---------- 20. Motion — the authored moment: lines drafting themselves ----------
   Every hidden start state is gated behind html.motion, which JS sets only when it
   is able to reveal it again. Without JS, with reduced motion, or if anything
   throws, the page renders fully visible. Content is never trapped. */
.motion .draw{transform:scaleX(0)}
.motion .is-in .draw,.motion .draw.is-in{transform:scaleX(1);transition:transform .8s var(--ease)}

.motion .rise{opacity:0;transform:translateY(14px)}
.motion .is-in .rise,.motion .rise.is-in{opacity:1;transform:none;
  transition:opacity .6s var(--ease),transform .6s var(--ease)}
.motion .is-in .rise:nth-child(2){transition-delay:.07s}
.motion .is-in .rise:nth-child(3){transition-delay:.14s}

.motion .survey-line{opacity:0;transform:translateY(10px)}
.motion .is-in .survey-line{opacity:1;transform:none;
  transition:opacity .55s var(--ease),transform .55s var(--ease)}
.motion .is-in .survey-line:nth-child(2){transition-delay:.12s}
.motion .is-in .survey-line:nth-child(3){transition-delay:.24s}

.motion .verdict{opacity:0;transform:translateY(12px)}
.motion .is-in .verdict{opacity:1;transform:none;
  transition:opacity .7s var(--ease) .38s,transform .7s var(--ease) .38s}

.motion .brick-fill{opacity:0}
.motion .brick-fill.set{opacity:1;transition:opacity .5s var(--ease)}

/* Spec rows are courses. They lay in bottom-of-the-list upward the same way a
   wall does, and the leader dots run out to meet the value. */
.motion .spec li{opacity:0;transform:translateY(8px)}
.motion .is-in .spec li{opacity:1;transform:none;
  transition:opacity .5s var(--ease),transform .5s var(--ease)}
.motion .is-in .spec li:nth-child(1){transition-delay:.05s}
.motion .is-in .spec li:nth-child(2){transition-delay:.13s}
.motion .is-in .spec li:nth-child(3){transition-delay:.21s}
.motion .is-in .spec li:nth-child(4){transition-delay:.29s}
.motion .is-in .spec li:nth-child(5){transition-delay:.37s}
.motion .spec .dots{transform:scaleX(0);transform-origin:left center}
.motion .is-in .spec .dots{transform:scaleX(1);transition:transform .55s var(--ease) .1s}

/* A field report is written into the log: its rule is drawn, then the entry
   arrives under it. */
.motion .reviews-list li{opacity:0}
.motion .is-in .reviews-list li{opacity:1;transition:opacity .55s var(--ease)}
.motion .reviews-list li > *{transform:translateY(10px)}
.motion .is-in .reviews-list li > *{transform:none;transition:transform .6s var(--ease)}
.motion .is-in .reviews-list li:nth-child(1){transition-delay:.04s}
.motion .is-in .reviews-list li:nth-child(2){transition-delay:.12s}
.motion .is-in .reviews-list li:nth-child(3){transition-delay:.20s}
.motion .is-in .reviews-list li:nth-child(4){transition-delay:.28s}
.motion .is-in .reviews-list li:nth-child(5){transition-delay:.36s}
.motion .is-in .reviews-list li:nth-child(n+2) > *{transition-delay:inherit}

/* The rating is the one number on the page that is pure proof, so the stars
   are struck one at a time rather than appearing as a block. */
.motion .stars use{opacity:0;transform:scale(.72);transform-origin:center;
  transform-box:fill-box}
.motion .is-in .stars use{opacity:1;transform:none;
  transition:opacity .3s var(--ease),transform .42s var(--ease)}
.motion .is-in .stars use:nth-child(1){transition-delay:.10s}
.motion .is-in .stars use:nth-child(2){transition-delay:.18s}
.motion .is-in .stars use:nth-child(3){transition-delay:.26s}
.motion .is-in .stars use:nth-child(4){transition-delay:.34s}
.motion .is-in .stars use:nth-child(5){transition-delay:.42s}

/* Formats arrive as a set, under their own rules. */
.motion .formats li{opacity:0;transform:translateY(9px)}
.motion .is-in .formats li{opacity:1;transform:none;
  transition:opacity .5s var(--ease),transform .5s var(--ease)}
.motion .is-in .formats li:nth-child(2){transition-delay:.1s}

@media (prefers-reduced-motion:reduce){
  .motion .draw,.motion .rise,.motion .survey-line,.motion .verdict,
  .motion .spec li,.motion .spec .dots,.motion .reviews-list li,
  .motion .reviews-list li > *,.motion .stars use,.motion .formats li{
    opacity:1;transform:none;transition:none}
  .motion .brick-fill{opacity:1}
  .tbbar{transition:none}
  *{animation:none!important}
}

/* CONNECT (the universal inquiry form, assets/connect.css) in the Chris Scott blue.
   connect.css loads first; these later rules win at equal specificity. */
.cx{--cx-accent:#1D4086;--cx-accent-soft:rgba(29,64,134,.09)}
.on-blue .cx,.on-ink .cx{--cx-accent:#fff;--cx-accent-ink:#0D1C3B;--cx-accent-soft:rgba(255,255,255,.12)}
