/* The firm: "the name on the door"
   A stone tablet on a limestone wall, beside a navy door: the firm's name is cut into it.
   Two layouts:
   - gallery (default: no JavaScript, reduced motion, very short screens): each chapter has its own
     small tablet on its own piece of wall, with the year and the line below it
   - stage (JavaScript and motion allowed): one tablet on a sticky wall (beside the chapters on wide
     screens, a band under the header on phones); the name is re-cut as the chapters scroll past.
   The stage query must match LIVE in /js/firm.js, except for its "screen and": in print the stage
   queries do not match, so the page prints the gallery (a tablet per chapter) and not the sticky wall. */

.firm {
  --np-stone: var(--tablet-stone);                   /* the tablet's stone, grain and lip: styles.css */
  --np-grain: var(--tablet-grain);
  --np-cut: #5B544A;                                 /* a plain cut, its shaded face (the older names) */
  --np-lip: var(--tablet-lip);
  --np-edge: max(.5px, .035em) max(.7px, .05em) 0 var(--np-lip);
  --np-fresh: #F8F6F0;                               /* a fresh cut: pale stone dust */
  --np-shadow: rgba(64, 50, 30, .34);
  --firm-stone: linear-gradient(160deg, #F4E8CE 0%, #E7D4AE 52%, #D7BE93 100%);
  background: var(--stone-50);
}

.firm-intro { max-width: 40rem; }
.firm-chapters { list-style: none; }

.firm-year {
  font: 500 clamp(2.6rem, 2rem + 2.2vw, 3.5rem)/.95 var(--serif);
  font-variant-numeric: lining-nums; letter-spacing: -.02em; color: var(--navy);
}
.firm-year-to { font-size: .4em; font-style: italic; font-weight: 450; letter-spacing: 0; color: var(--orange-ink); white-space: nowrap; }
.firm-line { margin-top: 14px; max-width: 30em; font-size: 1.03rem; line-height: 1.62; color: var(--text); }

/* ------------------------------------------------------------ gallery layout (default) */
.firm-stage-col { display: none; }
.firm-chapters {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: clamp(52px, 6vw, 76px) clamp(28px, 4vw, 56px);
  margin-top: clamp(52px, 7vw, 84px);
}
.firm-ch-plate {
  position: relative; isolation: isolate; overflow: hidden;
  display: grid; place-items: center; aspect-ratio: 16 / 10;
  background: var(--firm-stone); border-radius: 2px;
}
.firm-ch-plate > .np { width: 70%; }
/* no two walls are cut the same (shifted, never mirrored: a mirror would light the joints from the right) */
.firm-ch:nth-child(even) .firm-ashlar { transform: translateX(-14%) scale(1.3); }
.firm-ch:nth-child(n + 3) .firm-ashlar { transform: translateY(-9%) scale(1.2); }
.firm-ch:nth-child(4) .firm-ashlar { transform: translate(8%, -9%) scale(1.3); }
.firm-ch-text { margin-top: 26px; }

@media (min-width: 960px) {
  .firm-chapters { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 959px) {
  /* on phones the wall runs edge to edge */
  .firm-ch-plate { margin-inline: calc(-1 * var(--gutter)); aspect-ratio: auto; padding: 30px var(--gutter); border-radius: 0; }
  .firm-ch-plate > .np { width: min(80%, 360px); }
  .firm-ch-text { margin-top: 22px; }
}

/* ------------------------------------------------------------ limestone */
.firm-ashlar { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; }
/* raking light from the upper left, and the grain of globigerina limestone */
.firm-light {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    radial-gradient(90% 70% at 40% 6%, rgba(255, 248, 230, .55), rgba(255, 248, 230, 0) 70%),
    linear-gradient(180deg, rgba(120, 88, 44, 0) 55%, rgba(120, 88, 44, .18));
}
.firm-light::after {
  content: ""; position: absolute; inset: 0; opacity: .2; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------ the stone tablet */
/* A dressed tablet of pale hard limestone, finer and a little greyer than the ashlar, set on the wall
   with a chamfered edge. The stone is a small tile (tools/build_tablet.py); the light on it, from the
   upper left as on the wall, is two gradients over it (no blend mode, no filter). */
.np {
  position: relative; container-type: inline-size; aspect-ratio: 1.72;
  border-radius: 1px; isolation: isolate;
  -webkit-user-select: none; user-select: none; /* decorative: keep it out of copied text */
  background:
    radial-gradient(120% 110% at 10% -6%, rgba(255, 253, 246, .5), rgba(255, 253, 246, 0) 58%),
    linear-gradient(172deg, rgba(92, 78, 58, 0) 42%, rgba(92, 78, 58, .13) 100%),
    var(--np-grain) 0 0 / 180px 180px,
    var(--np-stone);
  box-shadow:
    0 0 0 .5px rgba(96, 78, 52, .28),       /* the arris against the wall */
    1px 2px 2px rgba(64, 50, 30, .3),        /* where it meets the wall */
    5px 10px 18px -8px var(--np-shadow);     /* the soft shadow it casts, down and to the right */
}
/* the chamfer round the edge: lit along the top and left, in shade along the bottom and right
   (a border's corners are mitred, so the four faces meet on the diagonals, as a chamfer's do) */
.np::before {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none;
  border: max(3px, 2.1cqi) solid;
  border-color: rgba(255, 253, 247, .62) rgba(88, 74, 54, .15) rgba(88, 74, 54, .3) rgba(255, 253, 247, .38);
}
/* the cut margin line: a fine V-cut, shaded above and to the left, lit below and to the right */
.np::after {
  content: ""; position: absolute; inset: 5.4cqi; pointer-events: none;
  border: 1px solid rgba(88, 74, 54, .4);
  box-shadow: inset 1px 1px 0 rgba(255, 253, 247, .75), 1px 1px 0 rgba(255, 253, 247, .75);
}

.np-face {
  position: absolute; inset: 8.4cqi 8cqi 7.2cqi; z-index: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  text-align: center;
}
.np-names { flex: 1; display: grid; width: 100%; align-items: center; }
.np-layer { grid-area: 1 / 1; }
.np-name {
  --fill: var(--np-cut);
  margin: 0; display: grid; grid-template-rows: 10.5cqi 10cqi 6.6cqi; align-items: center; justify-items: center;
  font-family: var(--serif); font-weight: 500; text-transform: uppercase; white-space: nowrap; color: var(--fill);
}
/* today's name has navy paint in the cut, as the carving in the intro */
.np-name[data-fill="navy"] { --fill: var(--navy); }
.np-row { display: block; line-height: 1; }
.np-top { align-self: end; font-size: 3.7cqi; letter-spacing: .34em; padding: 0 0 1.6cqi .34em; }
.np-lg { font-size: 6.6cqi; letter-spacing: .07em; padding-left: .07em; }
.np-sub { align-self: start; font-size: 4.1cqi; letter-spacing: .24em; padding: 1.2cqi 0 0 .24em; }

/* a V-cut letter in raking light: the shaded face shows as the letter, the lit lower/right face as its lip */
.np-c { display: inline-block; color: var(--fill); text-shadow: var(--np-edge); }
/* the monogram is cut in one piece and painted; freshly cut, its square is a shallow recess in shade.
   Its lip is a drop-shadow, a little deeper than the letters': under 1px down, it barely shows in either engine */
.np-mark {
  --np-fresh: #CEC7B9;
  display: inline-block; vertical-align: bottom; height: 8.6cqi; width: auto; margin-bottom: .2cqi;
  filter: drop-shadow(.6px 1.1px 0 var(--np-lip));
}

.np-foot {
  display: flex; align-items: center; justify-content: center; gap: 2.2cqi; width: 100%; margin: 0;
  font: 500 2.3cqi/1 var(--serif); letter-spacing: .34em; text-transform: uppercase; white-space: nowrap;
  color: #57514A; /* shallow-cut: 5.3:1 or more where the tablet is darkest */
  text-shadow: max(.4px, .03em) max(.6px, .06em) 0 var(--np-lip);
}
.np-foot::before, .np-foot::after {
  content: ""; flex: 1; max-width: 9cqi; height: 1px;
  background: rgba(88, 74, 54, .45); box-shadow: 1px 1px 0 rgba(255, 253, 247, .75);
}
.np-foot-dot { width: .7cqi; min-width: 2px; aspect-ratio: 1; border-radius: 50%; background: #6B645A; box-shadow: .5px .5px 0 var(--np-lip); margin-right: .34em; }
/* too small to read on a little tablet: leave it off */
@container (max-width: 300px) { .np-foot { display: none; } }

/* ------------------------------------------------------------ re-cutting (big tablet only) */
/* a soft pass of pale stone dust crosses the tablet as the old name is dressed away */
.np-sweep { position: absolute; inset: 0; z-index: 2; border-radius: inherit; overflow: hidden; pointer-events: none; }
/* The band's side edges must be fully transparent: at 100deg the gradient's 0% and 100% lines only
   touch the corners, so the stops are padded in (the side edges fall inside the first and last 17%). */
.np-sweep-band {
  position: absolute; top: -10%; bottom: -10%; left: 0; width: 60%;
  background: linear-gradient(100deg,
    rgba(250, 248, 242, 0) 22%, rgba(250, 248, 242, .3) 38%, rgba(252, 251, 247, .55) 50%,
    rgba(250, 248, 242, .3) 62%, rgba(250, 248, 242, 0) 78%);
  transform: translate3d(-100%, 0, 0); /* off the tablet; firm.js sweeps it to 170% */
}
/* the chisel: a small white point of light that travels with the cut */
.np-burin {
  position: absolute; left: 0; top: 0; z-index: 3; width: 5cqi; height: 5cqi; margin: -2.5cqi 0 0 -2.5cqi;
  border-radius: 50%; pointer-events: none; opacity: 0;
  background: radial-gradient(circle, #fff 0 7%, rgba(255, 254, 250, .75) 16%, rgba(255, 252, 244, .28) 38%, rgba(255, 252, 244, 0) 66%);
}

/* Blank: the tablet is smooth and empty until it comes into view. */
.np-layer.is-blank .np-c { clip-path: inset(0 100% 0 0); }

/* Cut: each letter is cut left to right. A fresh cut shows pale stone dust and the shade of its upper
   edge; then the shading of the cut (and on today's name, the paint) settles in.
   --t (the moment the chisel reaches the letter) is set per letter by firm.js.
   The clip ends as none, not inset(0): a clip also cuts off the monogram's lip, just outside its box. */
.np-layer.is-cut .np-c {
  animation: np-cut var(--cut, 640ms) linear both;
  animation-delay: var(--t, calc(var(--i) * 46ms));
}
@keyframes np-cut {
  0% { clip-path: inset(0 100% 0 0); color: var(--np-fresh); text-shadow: 0 -.04em 0 rgba(88, 74, 54, .55); animation-timing-function: cubic-bezier(.3, .1, .3, 1); }
  30% { clip-path: inset(0 0 0 0); color: var(--np-fresh); text-shadow: 0 -.04em 0 rgba(88, 74, 54, .55); animation-timing-function: cubic-bezier(.3, .6, .3, 1); }
  100% { clip-path: none; color: var(--fill); text-shadow: var(--np-edge); }
}

/* Out: the old name is filled and dressed smooth as the dust passes over it (--o per letter):
   its lit edge goes first, then the letter. */
.np-layer.is-out .np-c {
  animation: np-out var(--out, 420ms) cubic-bezier(.4, 0, .2, 1) both;
  animation-delay: var(--o, 0ms);
}
.np-layer.is-out .np-c.is-skip { visibility: hidden; animation: none; }
@keyframes np-out {
  45% { opacity: 1; color: #B9B1A3; text-shadow: 0 0 0 transparent; }
  100% { opacity: 0; color: var(--np-stone); text-shadow: 0 0 0 transparent; }
}

/* ------------------------------------------------------------ the wall of the stage */
.firm-wall { position: relative; isolation: isolate; overflow: hidden; background: var(--firm-stone); border-radius: 2px; }

/* the office door: painted navy, cropped at the left edge, in a limestone surround */
.firm-door {
  position: absolute; left: 0; top: 0; bottom: 0; width: 14%;
  background:
    radial-gradient(120% 50% at 30% 0%, rgba(120, 136, 196, .22), rgba(120, 136, 196, 0) 70%),
    linear-gradient(180deg, rgba(8, 11, 26, 0) 60%, rgba(8, 11, 26, .3)),
    linear-gradient(90deg, #1D2549 0%, #2B3565 58%, #242D58 100%);
}
.firm-door::after { /* the shadow the surround throws into the doorway */
  content: ""; position: absolute; top: 0; bottom: 0; right: 0; width: 24%;
  background: linear-gradient(90deg, rgba(8, 11, 26, 0), rgba(8, 11, 26, .38));
}
.firm-door-panel { /* a raised panel in a moulding: lit on its upper edges, shaded below */
  position: absolute; left: -40%; right: 24%; top: 7%; height: 40%; border-radius: 1px;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0) 60%, rgba(255, 255, 255, .04));
  box-shadow:
    0 0 0 1px rgba(6, 9, 24, .45),
    1px 1px 0 1px rgba(160, 172, 220, .16),
    inset 0 0 0 6px #2F3A6B,
    inset 1px 1px 0 6px rgba(170, 182, 230, .16),
    inset -1px -1px 0 7px rgba(6, 9, 24, .38);
}
.firm-door-panel-low { top: 53%; }
.firm-door-knob { /* a brass knob on the lock stile */
  position: absolute; right: 28%; top: 49.5%; width: 17%; max-width: 20px; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle at 36% 30%, #FFF3CC 0 9%, #E4BE6C 30%, #A87A2E 68%, #5E4217 100%);
  box-shadow: 0 0 0 3px rgba(20, 26, 60, .5), 3px 5px 7px rgba(4, 6, 18, .55);
}
.firm-jamb {
  position: absolute; top: 0; bottom: 0; left: 14%; width: 4.4%;
  background: linear-gradient(90deg, #C8AD80 0%, #FBF1DC 18%, #EEDDBA 55%, #D9C198 86%, #BFA277 100%);
  box-shadow: 10px 0 22px -6px rgba(80, 56, 22, .38);
}
.firm-jamb::before { /* a moulded edge: one fine groove along the surround */
  content: ""; position: absolute; top: 0; bottom: 0; left: 38%; width: 1px;
  background: rgba(120, 90, 50, .4); box-shadow: 1px 0 0 rgba(255, 248, 230, .7);
}

/* where the tablet is set: at eye level on the wall, beside the door */
.firm-mount { position: absolute; left: 26%; width: 67%; top: 46%; transform: translateY(-50%); }

/* ------------------------------------------------------------ the year rail */
.firm-rail { position: relative; }
.firm-rail ol { list-style: none; display: grid; grid-template-columns: repeat(4, 1fr); }
/* a quiet scale that follows the name on the tablet: it is decoration, not a control */
.firm-rail li {
  display: flex; flex-direction: column; align-items: center; gap: 11px;
  font: 500 .72rem/1 var(--sans); letter-spacing: .14em; color: var(--muted);
  font-variant-numeric: tabular-nums; transition: color .5s ease; cursor: default;
}
.firm-rail li.is-on { color: var(--navy); }
.firm-rail-dot {
  position: relative; z-index: 1; width: 7px; height: 7px; border-radius: 50%;
  background: var(--stone-50); box-shadow: inset 0 0 0 1px var(--navy-300);
  transition: background-color .5s ease, box-shadow .5s ease;
}
.firm-rail li.is-past .firm-rail-dot,
.firm-rail li.is-on .firm-rail-dot { background: var(--orange); box-shadow: none; }
.firm-rail-track { position: absolute; left: 12.5%; right: 12.5%; top: 3px; height: 1px; background: var(--line); }
.firm-rail-fill {
  position: absolute; inset: 0; background: var(--orange);
  transform: scaleX(0); transform-origin: left center; transition: transform 1s var(--ease);
}

/* ------------------------------------------------------------ stage layout (JavaScript on, motion allowed) */
@media screen and (prefers-reduced-motion: no-preference) and (min-height: 540px) {
  .js .firm:not(.is-static) .firm-ch-plate { display: none; }
  .js .firm:not(.is-static) .firm-chapters { display: block; margin-top: 0; }
  .js .firm:not(.is-static) .firm-ch { display: flex; flex-direction: column; justify-content: center; }
  .js .firm:not(.is-static) .firm-ch-text { margin-top: 0; }
  .js .firm:not(.is-static) .firm-ch-text::before {
    content: ""; display: block; width: 44px; height: 2px; margin-bottom: 22px; background: var(--orange);
    transform: scaleX(0); transform-origin: left center; transition: transform .8s var(--ease);
  }
  .js .firm:not(.is-static) .firm-ch.is-active .firm-ch-text::before { transform: scaleX(1); }
  .js .firm:not(.is-static) .firm-year { color: var(--navy-400); transition: color .6s ease; }
  .js .firm:not(.is-static) .firm-ch.is-active .firm-year { color: var(--navy); }
  .js .firm:not(.is-static) .firm-line { color: var(--muted); transition: color .6s ease; }
  .js .firm:not(.is-static) .firm-ch.is-active .firm-line { color: var(--text); }
}

/* phones and tablets: the wall is a band that stays under the header while the chapters pass beneath */
@media screen and (prefers-reduced-motion: no-preference) and (min-height: 540px) and (max-width: 959px) {
  .js .firm:not(.is-static) .firm-stage-col { display: contents; }
  .js .firm:not(.is-static) .firm-intro { position: relative; z-index: 3; }
  .js .firm:not(.is-static) .firm-stage {
    --pw: min(74vw, 340px, calc((27vh - 30px) * 1.72));
    position: sticky; top: var(--header-h); z-index: 2; display: block;
    margin: clamp(40px, 9vw, 60px) calc(-1 * var(--gutter)) 0;
  }
  /* the band runs up behind the frosted header, so a chapter that has slid under it does not show
     again above it (the intro paints over this, so it never hides the lead paragraph) */
  .js .firm:not(.is-static) .firm-stage::before {
    content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: var(--header-h);
    background: var(--stone-50); pointer-events: none;
  }
  /* the chapters slide softly under the band */
  .js .firm:not(.is-static) .firm-stage::after {
    content: ""; position: absolute; left: 0; right: 0; top: 100%; height: clamp(48px, 7.5vh, 76px); pointer-events: none;
    background: linear-gradient(var(--stone-50) 0%, rgba(247, 243, 236, .9) 28%, rgba(247, 243, 236, .55) 62%, rgba(247, 243, 236, 0) 100%);
  }
  .js .firm:not(.is-static) .firm-wall { height: calc(var(--pw) / 1.72 + 34px); border-radius: 0; }
  .js .firm:not(.is-static) .firm-door { width: 8%; }
  .js .firm:not(.is-static) .firm-door-panel { right: 18%; }
  .js .firm:not(.is-static) .firm-door-knob { display: none; }
  .js .firm:not(.is-static) .firm-jamb { left: 8%; width: 2.6%; }
  .js .firm:not(.is-static) .firm-mount { top: 50%; left: calc(10.6% + (89.4% - var(--pw)) / 2); width: var(--pw); }
  /* the rail becomes a thin line along the foot of the band */
  .js .firm:not(.is-static) .firm-rail { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; }
  .js .firm:not(.is-static) .firm-rail ol { display: none; }
  .js .firm:not(.is-static) .firm-rail-track { left: 0; right: 0; top: 0; height: 2px; background: rgba(143, 116, 80, .3); }

  .js .firm:not(.is-static) .firm-chapters { padding: 0 0 4vh; }
  .js .firm:not(.is-static) .firm-ch {
    justify-content: flex-start; padding: clamp(40px, 8vh, 72px) 0 12px;
    min-height: 34vh; min-height: 34svh;
  }
  .js .firm:not(.is-static) .firm-line { font-size: 1.08rem; }
  .js .firm:not(.is-static) .firm-year { font-size: clamp(3rem, 2.2rem + 3vw, 3.9rem); }
}
@media screen and (prefers-reduced-motion: no-preference) and (min-height: 540px) and (min-width: 700px) and (max-width: 959px) {
  .js .firm:not(.is-static) .firm-ch { min-height: 30vh; min-height: 30svh; }
}

/* wide screens: the wall stays beside the chapters */
@media screen and (prefers-reduced-motion: no-preference) and (min-height: 540px) and (min-width: 960px) {
  .js .firm:not(.is-static) .firm-layout {
    display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    column-gap: clamp(40px, 6vw, 104px);
  }
  .js .firm:not(.is-static) .firm-intro { grid-column: 1; grid-row: 1; }
  .js .firm:not(.is-static) .firm-story { display: contents; }
  .js .firm:not(.is-static) .firm-stage-col { display: block; grid-column: 2; grid-row: 1 / span 2; }
  /* the wall is at most 820px tall; on taller screens it is centred in the space below the header,
     level with the chapter being read (firm.js reads at the middle of the screen) */
  .js .firm:not(.is-static) .firm-stage {
    position: sticky; top: max(calc(var(--header-h) + 12px), calc((100vh + var(--header-h) - 820px) / 2));
    height: min(calc(100vh - var(--header-h) - 40px), 820px);
    display: flex; flex-direction: column; gap: 24px;
  }
  .js .firm:not(.is-static) .firm-wall { flex: 1; }
  .js .firm:not(.is-static) .firm-chapters { grid-column: 1; grid-row: 2; padding-bottom: 18vh; }
  .js .firm:not(.is-static) .firm-ch { min-height: 62vh; }
  .js .firm:not(.is-static) .firm-ch:first-child { min-height: 52vh; }
  .js .firm:not(.is-static) .firm-year { font-size: clamp(4.4rem, 2.2rem + 4vw, 6.6rem); line-height: .9; }
  .js .firm:not(.is-static) .firm-line { margin-top: 22px; max-width: 24em; font-size: 1.08rem; }
}

/* ------------------------------------------------------------ forced colours */
@media (forced-colors: active) {
  /* the chamfer is a wide border, which forced colours would draw as a thick frame; the grain is a
     picture, which forced colours keep, and the letters would sit on blocky backplates over it */
  .np::before { display: none; }
  .np { outline: 1px solid CanvasText; background-image: none; }
  /* an SVG keeps its own colour (navy), which all but vanishes on a dark Canvas; the cut animates
     its colour through these two, so they are set too */
  .np-mark { --fill: CanvasText; --np-fresh: CanvasText; color: CanvasText; filter: none; }
  /* the foot's dot and its two rules are backgrounds, which forced colours would blank out */
  .np-foot::before, .np-foot::after, .np-foot-dot { forced-color-adjust: none; background: CanvasText; box-shadow: none; }
}
/* ------------------------------------------------------------ print: the gallery, a chapter never split across pages */
@media print {
  .firm-ch { break-inside: avoid; }
  /* backgrounds are not printed: the tablets print as outlines with dark letters */
  .np::before { display: none; }
  .np { box-shadow: none; outline: 1px solid #999; }
  .np-c { text-shadow: none; }
  .np-mark { filter: none; }
  /* but the foot's dot and its two rules are drawn as backgrounds: keep them */
  .np-foot::before, .np-foot::after, .np-foot-dot { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}
