/* ============================================================
   inframes design system
   Layered on top of Bootstrap 5. Tokens are from CLAUDE.md section 5.
   Nothing here overrides Bootstrap except by intent; the custom
   properties feed Bootstrap's own variables where they overlap.
   ============================================================ */

:root {
  /* Palette, drawn from the materials of the largest client:
     cast iron, ash, firebrick, ember, flue steel. */
  --ink:        #171614;
  --ink-2:      #55534D;
  --ink-3:      #8B887F;
  --paper:      #EBEAE6;
  --surface:    #F6F5F2;
  --rule:       #D6D4CD;
  --ember:      #B33A15;
  --ember-soft: #F3E4DD;
  --slate:      #3E4A52;

  /* Derived, not in the brief. Ember at 2.6:1 on ink fails contrast,
     so dark panels get a lifted ember. Same hue, raised luminance. */
  --ember-lift: #E2734B;

  --sans:  'Schibsted Grotesk', system-ui, -apple-system, sans-serif;
  --serif: 'Newsreader', Georgia, 'Times New Roman', serif;
  --mono:  'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;

  /* One spacing scale, used everywhere. */
  --gap-1: 6px;
  --gap-2: 12px;
  --gap-3: 20px;
  --gap-4: 32px;
  --gap-5: 52px;
  --gap-6: 84px;

  --measure: 62ch;
  --shell: 1180px;

  /* Bootstrap overrides fed from our own tokens */
  --bs-body-bg: var(--paper);
  --bs-body-color: var(--ink);
  --bs-body-font-family: var(--sans);
  --bs-link-color: var(--ember);
  --bs-link-hover-color: var(--ink);
  --bs-border-color: var(--rule);
  --bs-border-radius: 0;
}

/* ---------- base ---------- */

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 18px;
  line-height: 1.65;
  font-weight: 400;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

/* Hard edges throughout. No rounded corners, no shadows.
   This is the single most consistent quality of the references. */
img, video, .btn, .panel, .log, input, textarea { border-radius: 0; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--ember);
  outline-offset: 3px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--ink);
  color: var(--paper);
  padding: var(--gap-2) var(--gap-3);
  z-index: 200;
  font-size: 15px;
}
.skip:focus { left: 0; }

/* ---------- shell ---------- */

.shell {
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(16px, 4vw, 24px);
}

.measure { max-width: var(--measure); }

/* ---------- type ---------- */

h1, h2, h3, h4 {
  font-family: var(--sans);
  font-weight: 600;
  letter-spacing: -0.022em;
  margin: 0;
  text-wrap: balance;
}

h1 {
  font-size: clamp(38px, 6vw, 66px);
  line-height: 1.03;
  letter-spacing: -0.032em;
  max-width: 15ch;
}

/* Heading marks: a short ember underline and an ember full stop.
   Both borrowed from the reference set, where colour arrives as
   punctuation rather than as a surface. */
h1.marked,
h2.marked {
  position: relative;
  padding-bottom: 26px;
  margin-bottom: var(--gap-4);
}

h1.marked::before,
h2.marked::before {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 58px;
  height: 3px;
  background: var(--ember);
}

h1.marked::after,
h2.marked::after {
  content: '.';
  color: var(--ember);
}

.panel h2.marked::before { background: var(--ember-lift); }
.panel h2.marked::after { color: var(--ember-lift); }

h2 {
  font-size: clamp(26px, 3.1vw, 37px);
  line-height: 1.14;
  letter-spacing: -0.026em;
  max-width: 20ch;
}

h3 {
  font-size: clamp(19px, 1.6vw, 22px);
  line-height: 1.28;
  max-width: 28ch;
}

p { margin: 0 0 var(--gap-3); }
p:last-child { margin-bottom: 0; }

.lede {
  font-size: clamp(19px, 1.9vw, 23px);
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 48ch;
  letter-spacing: -0.012em;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 var(--gap-3);
}

/* The serif is reserved for passages meant to be read slowly. */
.read {
  font-family: var(--serif);
  font-size: 20px;
  line-height: 1.7;
  max-width: var(--measure);
}

.small { font-size: 16px; color: var(--ink-2); }

.cap {
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--ink-3);
  margin-top: var(--gap-3);
}

/* ---------- masthead ---------- */

.bar {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}

/* Everything in the bar scales with the viewport rather than stepping at
   breakpoints, so there is no width at which the Menu button is pushed off
   the edge. The button and the telephone number never shrink; the logo does. */
.bar-in {
  display: flex;
  align-items: center;
  gap: clamp(10px, 2.6vw, 20px);
  height: 62px;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  margin-right: auto;
  min-width: 0;
  flex-shrink: 1;
  color: var(--ink);
  text-decoration: none;
}
/* Width-driven, so the logo shrinks predictably instead of holding its
   height and pushing the Menu button off the edge on a narrow handset. */
.wordmark img {
  width: clamp(96px, 34vw, 204px);
  height: auto;
  display: block;
}

/* The telephone number is the proposition, not decoration,
   so it stays visible at every width. */
.bar-tel {
  font-family: var(--mono);
  font-size: clamp(12px, 3vw, 14.5px);
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
  flex-shrink: 0;
}
.bar-tel:hover { color: var(--ember); }

.menu-btn {
  font-family: var(--sans);
  font-size: clamp(13px, 3vw, 14.5px);
  font-weight: 500;
  letter-spacing: 0.02em;
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--ink);
  padding: 7px clamp(11px, 3vw, 15px);
  cursor: pointer;
  line-height: 1.2;
  flex-shrink: 0;
  white-space: nowrap;
}
.menu-btn:hover { background: var(--ink); color: var(--paper); }

/* ---------- drawer ---------- */

/* Fills the screen at every width. On desktop the content sits inside the
   same shell measure as the page, so the nav lines up with the masthead
   rather than floating in the middle of a black field. */
.offcanvas.drawer {
  background: var(--ink);
  color: var(--paper);
  border: 0;
  width: 100%;
  max-width: 100%;
}

.drawer-in {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding: 16px clamp(16px, 4vw, 24px) clamp(24px, 5vw, 44px);
}

.drawer-head {
  display: flex;
  align-items: center;
  gap: clamp(10px, 2.6vw, 20px);
  height: 62px;
  flex-shrink: 0;
}
.drawer-head .wordmark { color: var(--paper); margin-right: auto; }
.drawer-head .wordmark img { width: clamp(96px, 34vw, 204px); height: auto; display: block; }

.drawer-close {
  margin-left: auto;
  background: transparent;
  border: 1px solid rgba(235, 234, 230, 0.4);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 14.5px;
  font-weight: 500;
  padding: 7px 15px;
  cursor: pointer;
}
.drawer-close:hover { border-color: var(--paper); }

.drawer-nav {
  margin-top: auto;
  padding-top: var(--gap-5);
}

.drawer-nav a {
  display: block;
  font-size: clamp(25px, 4.4vw, 34px);
  font-weight: 600;
  letter-spacing: -0.028em;
  line-height: 1.16;
  text-decoration: none;
  color: var(--paper);
  padding: 5px 0;
}
.drawer-nav a:hover,
.drawer-nav a:focus-visible { color: var(--ember-lift); }
.drawer-nav a[aria-current='page'] { color: var(--ember-lift); }

.drawer-foot {
  margin-top: var(--gap-5);
  padding-top: var(--gap-3);
  border-top: 1px solid rgba(235, 234, 230, 0.22);
  font-family: var(--mono);
  font-size: 13.5px;
  line-height: 1.9;
  color: var(--ink-3);
}
.drawer-foot a { color: var(--paper); text-decoration: none; }
.drawer-foot a:hover { color: var(--ember-lift); }

/* ---------- sections ---------- */

.band { padding-block: var(--gap-6); }
.band + .band { border-top: 1px solid var(--rule); }
.band-tight { padding-block: var(--gap-5); }

@media (max-width: 720px) {
  :root { --gap-6: 56px; --gap-5: 40px; }
}

.stack > * + * { margin-top: var(--gap-4); }

/* Two columns on desktop, as in the reference set. Multi-column rather than
   grid, so prose flows down the first column and into the second, which is
   how a reader expects continuous text to run. */
.cols {
  column-count: 2;
  column-gap: 64px;
  orphans: 2;
  widows: 2;
}
.cols > p { margin-top: 0; }



@media (max-width: 900px) {
  .cols { column-count: 1; }
}

/* Ink panel. The one full-bleed contrast device, borrowed from the
   editorial references. Used once per page at most. */
.panel {
  background: var(--ink);
  color: var(--paper);
  padding-block: var(--gap-6);
}
.panel h2 { color: var(--paper); }
.panel .small { color: #C9C6BE; }
.panel a { color: var(--ember-lift); }
.panel .rule-off { border-color: rgba(235, 234, 230, 0.22); }

/* ---------- the sentences: the signature block ----------
   Client instructions arrive as separate messages, so they are set as
   separate lines rather than as the semicolon-joined paragraph they are
   in the copy. The structure encodes something true about the content. */

.sentences {
  border-left: 2px solid var(--ember);
  padding-left: var(--gap-3);
  margin: var(--gap-4) 0 0;
  max-width: 54ch;
}

.sentences li {
  font-family: var(--serif);
  font-size: clamp(17px, 1.75vw, 20px);
  line-height: 1.45;
  color: var(--ink);
  list-style: none;
  padding: 7px 0;
}
.sentences { list-style: none; }
.sentences li + li { border-top: 1px solid var(--rule); }

/* ---------- figures ---------- */

.figure-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  margin-top: var(--gap-4);
}

.figure {
  background: var(--paper);
  padding: var(--gap-3) 18px;
}
.panel .figure { background: var(--ink); }

.figure-n {
  font-family: var(--mono);
  font-size: 27px;
  line-height: 1.05;
  color: var(--ember);
  margin-bottom: var(--gap-1);
  letter-spacing: -0.02em;
}
.panel .figure-n { color: var(--ember-lift); }

.figure-l {
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-2);
}
.panel .figure-l { color: #C9C6BE; }

/* Prose set under a figure row needs the row to breathe. The prototypes carried
   this as an inline margin-top on the text block; it belongs here. */
.figure-row + .entry { margin-top: var(--gap-5); }

/* ---------- work log band: the page's one real artefact ----------
   Not meant to be read. Meant to register as density. */

/* The log sits at a slight angle inside a square frame. The frame clips it,
   so the edges the reader sees are horizontal and vertical while the lines
   of work run off at a tilt. Scaled up enough that no corner shows through. */
.log-frame {
  position: relative;
  overflow: hidden;
  max-height: 320px;
  margin-top: var(--gap-4);
}

.log {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--rule);
  padding: 26px 22px;
  margin: 0;
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 2;
  color: var(--ink-2);
  transform: rotate(-2deg) scale(1.08);
  transform-origin: center;
}

.log dt {
  display: inline-block;
  width: 52px;
  color: var(--ink-3);
  font-weight: 400;
}
.log dd { display: inline; margin: 0; }
/*.log div + div { margin-top: 0; }*/

.log-frame dl.log div {margin-left:30px;}
.log-frame dl.log {margin-top:-25px;}

/* The fade belongs to the frame, not the log, so it stays horizontal
   while the log underneath it is tilted. */
.log-frame::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 110px;
  background: linear-gradient(to bottom, rgba(235, 234, 230, 0), var(--paper));
  pointer-events: none;
}

/* ---------- buttons ---------- */

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-2);
  margin-top: var(--gap-4);
}

.btn-ember,
.btn-line {
  display: inline-block;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 500;
  padding: 13px 22px;
  text-decoration: none;
  border: 1px solid var(--ember);
  line-height: 1.2;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.btn-ember { background: var(--ember); color: var(--paper); }
.btn-ember:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }

.btn-line { background: transparent; color: var(--ember); }
.btn-line:hover { background: var(--ember); color: var(--paper); }

.panel .btn-ember { background: var(--ember-lift); border-color: var(--ember-lift); color: var(--ink); }
.panel .btn-ember:hover { background: var(--paper); border-color: var(--paper); }

.link {
  font-weight: 500;
  color: var(--ember);
  text-decoration: none;
  border-bottom: 1px solid var(--ember);
}
.link:hover { color: var(--ink); border-color: var(--ink); }

/* ---------- questions ----------
   Deliberately not an accordion. The brief requires the awkward
   questions answered on the page rather than hidden behind a click. */

.q + .q {
  margin-top: var(--gap-4);
  padding-top: var(--gap-4);
  border-top: 1px solid var(--rule);
}
.q h3 { margin-bottom: var(--gap-2); }

/* ---------- foot ---------- */

.foot {
  background: var(--ink);
  color: var(--ink-3);
  padding-block: var(--gap-5);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.9;
}
.foot a { color: var(--paper); text-decoration: none; }
.foot a:hover { color: var(--ember-lift); }

.foot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--gap-4);
}

.foot .wordmark { color: var(--paper); margin: 0 0 var(--gap-3); }
.foot .wordmark svg { height: 24px; }

/* Ember mid-dot as a separator, the reference's other colour device. */
.middot { color: var(--ember-lift); padding: 0 8px; }
.band .middot { color: var(--ember); }

/* ---------- motion ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ============================================================
   Homepage components
   ============================================================ */

/* Hard-edged split, from the Cool Hunting reference. The text column
   aligns to the shell; the image bleeds to the viewport edge. */
.hero {
  border-bottom: 1px solid var(--rule);
}

/* Full width, equal halves. The only horizontal padding is the ps-3 ps-lg-5
   on the section itself, so the text is not pushed towards the middle. */
.hero-text {
  padding-block: var(--gap-6);
  align-self: center;
}

/* overflow:hidden is load-bearing: the parallax image is deliberately taller
   than this frame so it has room to travel, and this is what hides the surplus. */
.hero-img { position: relative; min-height: 420px; overflow: hidden; }
.hero-img .ph, .hero-img img { position: absolute; inset: 0; height: 100%; width: 100%; }
.hero-img img { object-fit: cover; }

/* Below the lg breakpoint Bootstrap stacks the columns, so the text returns
   to ordinary container padding and the photograph sits above it. */
/* Stacked below lg. The bleed to the right edge is a desktop device: on a phone
   it just looks like the image has been cropped by accident, so the hero gets
   equal margins and the image sits square inside them. */
@media (max-width: 991.98px) {
  .hero {
    padding-right: 1rem;          /* matches the section's ps-3 on the left */
  }
  .hero-text {
    padding-block: var(--gap-5);
    padding-inline: 0;
  }
  .hero-img { min-height: 280px; order: -1; }
}

/* Placeholder. Deliberately plain, so an unfinished page reads as
   unfinished rather than broken. Delete .ph when the photograph lands. */
.ph {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--rule);
  padding: var(--gap-3);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.7;
  color: var(--ink-3);
}
.ph span { max-width: 30ch; }
.ph-4x3 { aspect-ratio: 4 / 3; }


.story h3 { margin: var(--gap-3) 0 var(--gap-2); }
.story p { font-size: 16.5px; color: var(--ink-2); }

.story-tag {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ember);
}

/* Price tiles: same grid as the figures, but the number carries a
   qualifier so "from" is not mistaken for the whole price. */
.price-n {
  font-family: var(--mono);
  font-size: 25px;
  line-height: 1.1;
  color: var(--ember);
  letter-spacing: -0.02em;
}
.price-q {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: block;
  margin-bottom: var(--gap-1);
}

/* The erosion passage is the one thing on the homepage meant to be read
   slowly, so it gets the ink panel and the serif. */
.panel .read { color: #DAD7D0; }
.panel .read strong { color: var(--paper); font-weight: 500; }

.story-img { width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; display: block; }

/* ---------- contact ---------- */

/* Each way of reaching us is a whole row and a whole tap target, because on a
   phone the point of this page is to make ringing up effortless. */
.contact-lines { border-top: 1px solid var(--rule); }

.contact-line {
  display: flex;
  align-items: baseline;
  gap: var(--gap-3);
  padding: var(--gap-3) 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  color: var(--ink);
}
.contact-line:hover { color: var(--ember); }

.contact-k {
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  flex: 0 0 92px;
}
/* All three values sit at the same size. min-width:0 and the wrap rule stop
   the long email address overflowing its flex column and being squashed
   smaller than the other two. */
.contact-v {
  font-size: 18px;   /* body size: these are details to read, not a headline */
  font-weight: 500;
  letter-spacing: -0.02em;
  min-width: 0;
  overflow-wrap: anywhere;
}

@media (max-width: 480px) {
  .contact-line { display: block; }
  .contact-k { display: block; margin-bottom: 2px; }
}

.postal {
  font-style: normal;
  font-family: var(--mono);
  font-size: 14.5px;
  line-height: 1.9;
  color: var(--ink-2);
}

/* ============================================================
   Page head: the child-page equivalent of the homepage hero.
   Same family, half the volume. Text and image side by side, but the
   image is capped in height so it illustrates the page rather than
   announcing it, and the band sits inside the container.
   ============================================================ */

.page-head { border-bottom: 1px solid var(--rule); padding-block: var(--gap-5); }

.page-head .lede { max-width: 44ch; }

.page-head-img {
  display: block;
  width: 100%;
  height: 100%;
  max-height: 340px;
  object-fit: cover;
  border: 1px solid var(--rule);
}

.page-head-fig { margin: 0; height: 100%; display: flex; flex-direction: column; justify-content: center; }
.page-head-fig .cap { margin-top: var(--gap-2); }

@media (max-width: 991.98px) {
  .page-head-img { max-height: 260px; }
}

/* ---------- site evolution strip ----------
   Frames share a width and keep their natural height, so a fixed-width
   site from 2003 reads as squat and a modern scrolling page reads as long.
   The change of shape is the argument, so do not crop them to a common box. */

.evo { align-items: start; }

.evo figure { margin: 0; }

.evo img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  background: var(--surface);
}

.evo figcaption {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding-top: var(--gap-2);
}
.evo figcaption b { color: var(--ember); font-weight: 400; }

/* ---------- pull quote ---------- */

.quote {
  border-left: 2px solid var(--ember);
  padding-left: var(--gap-4);
  margin: 0;
  max-width: 40ch;
}
.quote p {
  font-family: var(--serif);
  font-size: clamp(21px, 2.4vw, 27px);
  line-height: 1.42;
  color: var(--ink);
}
.quote figcaption {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-top: var(--gap-3);
}

/* ============================================================
   .entry — content written in the WordPress editor
   The templates own the page structure; this styles what an editor types
   inside it. Deliberately narrow: headings, prose, lists, quotes, images.
   ============================================================ */

.entry > *:first-child { margin-top: 0; }
.entry > *:last-child { margin-bottom: 0; }

.entry p,
.entry ul,
.entry ol { max-width: var(--measure); }

.entry h2 {
  margin-top: var(--gap-5);
  margin-bottom: var(--gap-3);
  position: relative;
  padding-bottom: 26px;
}
.entry h2::before {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 58px; height: 3px;
  background: var(--ember);
}
.entry h2::after { content: '.'; color: var(--ember); }

.entry h3 {
  margin-top: var(--gap-4);
  margin-bottom: var(--gap-2);
}

/* Bullets are kept to a minimum by the voice rules, but when the copy earns
   one it should not look like an afterthought. */
.entry ul, .entry ol { padding-left: 1.15em; margin-bottom: var(--gap-3); }
.entry li { margin-bottom: var(--gap-1); }
.entry ul li::marker { color: var(--ember); }

/* Buttons are excluded rather than patched afterwards. Undoing this rule with
   border-bottom: 0 also removed the bottom side of a button's own 1px box and
   left it three-sided. */
.entry a:not(.btn-ember):not(.btn-line) {
  color: var(--ember);
  text-decoration: none;
  border-bottom: 1px solid var(--ember);
}
.entry a:not(.btn-ember):not(.btn-line):hover { color: var(--ink); border-color: var(--ink); }

.entry blockquote {
  border-left: 2px solid var(--ember);
  padding-left: var(--gap-4);
  margin: var(--gap-4) 0;
  max-width: 40ch;
}
.entry blockquote p {
  font-family: var(--serif);
  font-size: clamp(21px, 2.4vw, 27px);
  line-height: 1.42;
}

.entry img { max-width: 100%; height: auto; border: 1px solid var(--rule); }
.entry figcaption {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-3);
  padding-top: var(--gap-2);
}

.entry hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: var(--gap-5) 0;
}

/* Two-column prose, where the editor asks for it with a wide block. */
.entry .cols { max-width: none; }

.pager { margin-top: var(--gap-5); font-family: var(--mono); font-size: 14px; }
.pager a { color: var(--ember); }

/* wp_nav_menu emits a real list; the drawer wants none of its furniture. */
.drawer-nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.drawer-nav-list li { list-style: none; }
.drawer-nav-list li::marker { content: none; }

.story h3 { margin-bottom: var(--gap-2); }
.story-link { text-decoration: none; }
.story-link:hover { color: var(--ember); }

/* Hero caption. A label along the bottom of the image rather than floating
   over it, where it would sooner or later land on something and stop being
   readable. Same hard edge and hairline as everything else. */
.hero-fig {
  position: absolute;
  inset: 0;
  margin: 0;
}
.hero-fig img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.hero-cap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--paper);
  border-top: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-3);
  padding: 9px clamp(12px, 2vw, 18px);
}

/* ---------- hero parallax ----------
   Driven by assets/js/inframes.js.

   Written first as a CSS scroll-driven animation (animation-timeline: view()),
   which is cheaper but only runs where scroll-driven animations have shipped,
   so most people saw nothing. Then rewritten with the drift tied to the hero's
   position in the viewport, which for a hero at the very top of the page moves
   it about thirty pixels across a whole screen of scrolling: working, and
   invisible. It is now tied to scroll distance, which is what parallax actually
   means and is plainly visible.

   The overhang is declared once, here, and read by the script, so the geometry
   and the movement cannot drift apart. The image is taller than its frame by
   twice the overhang and offset upward by one, giving it exactly that much room
   to travel in each direction without ever exposing an edge.

   Geometry is applied unconditionally: with object-fit: cover a slightly larger
   image looks identical, so a browser that never runs the script loses nothing. */

.hero-img {
  --hero-overhang: 90px;
}

/* One overhang, not two. The image travels from -overhang to 0, so it needs
   exactly that much extra height: with two, the bottom overhang is never
   scrolled into view and about an eighth of the file is downloaded to be
   discarded. */
.hero-img img {
  height: calc(100% + var(--hero-overhang));
  top: calc(-1 * var(--hero-overhang));
  bottom: auto;
}

.hero-img.is-parallax img { will-change: transform; }

/* The caption is a label on the frame, not part of the picture, so it stays
   still while the image moves behind it. */
.hero-cap { z-index: 2; }

@media (max-width: 991.98px) {
  /* Less room to travel on a phone, and a shorter hero to travel in. */
  .hero-img { --hero-overhang: 50px; }
}

/* Headings that are links.
   These sit outside .entry, because the section renderer lifts the heading out
   of the content wrapper, so the editor link rule never reached them and the
   seven service links on the hub page looked like plain headings. Underlined in
   the hairline colour rather than in ember: the heading is already doing the
   work, and ember at heading size would be a surface rather than punctuation. */
h1 a, h2 a, h3 a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-decoration-thickness: 1px;
  text-underline-offset: 7px;
  border-bottom: 0;
}
h1 a:hover, h2 a:hover, h3 a:hover,
h1 a:focus-visible, h2 a:focus-visible, h3 a:focus-visible {
  color: var(--ember);
  text-decoration-color: var(--ember);
}
.panel h2 a:hover { color: var(--ember-lift); text-decoration-color: var(--ember-lift); }

/* An H3 written inside a section sits within .entry, where the editor link rule
   outranks the heading rule on specificity and would give it both an underline
   and a border. Matched here with the same negations so it wins cleanly. */
.entry h2 a:not(.btn-ember):not(.btn-line),
.entry h3 a:not(.btn-ember):not(.btn-line) {
  border-bottom: 0;
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-decoration-thickness: 1px;
  text-underline-offset: 7px;
}
.entry h2 a:not(.btn-ember):not(.btn-line):hover,
.entry h3 a:not(.btn-ember):not(.btn-line):hover {
  color: var(--ember);
  text-decoration-color: var(--ember);
  border-color: transparent;
}
