/* =====================================================================
   Andrionis Group — "Antikythera"
   ---------------------------------------------------------------------
   The firm's name is Greek; the oldest surviving artifact of "verify the
   cycle by measurement" is a Greek bronze calculating instrument. So the
   page is built as an instrument: a patinated bronze-dark ground, hairline
   engraved geometry, one brass accent used where a pointer would be.

   Depth comes from layered structure — radial patina, concentric arcs, a
   fine grain — never from a soft gradient wash.

   Load order: styles/fonts.css (families) then this file.
   No inline styles anywhere: Task 12 sets style-src 'self'.
   ===================================================================== */

/* ---------------------------------------------------------------------
   1. Tokens
   ------------------------------------------------------------------ */

:root {
  /* Palette — verbatim from the approved design spec. Nothing else. */
  --ground: #0B1413;
  --ground-lift: #10201E;
  --verdigris: #3E8C7A;
  --verdigris-d: #2E6F62;
  --brass: #C08A3E;
  --brass-hot: #E5B25D;
  --text: #DCE6E1;
  --text-dim: #8FA9A1;
  --rule: rgba(220, 230, 225, 0.14);

  /* Alpha derivations of the palette above — same three colours, no new
     hues introduced. --rule is already defined this way in the spec. */
  --rule-soft: rgba(220, 230, 225, 0.07);
  --verdigris-line: rgba(62, 140, 122, 0.30);
  --verdigris-line-hi: rgba(62, 140, 122, 0.46);
  --patina-1: rgba(62, 140, 122, 0.20);
  --patina-2: rgba(46, 111, 98, 0.16);
  --brass-glow: rgba(192, 138, 62, 0.40);
  --well: rgba(6, 12, 11, 0.55);

  --display: "GFS Didot", Georgia, serif;
  --prose: "Newsreader", Georgia, serif;
  --mono: "Martian Mono", ui-monospace, monospace;

  /* Type scale. --step-0/2/4 are the spec's; -1/1/3 fill it in.
     Note: the h1 sits at --step-3, one stop below the top of the scale,
     because it is a 27-word sentence and not a three-word slogan. At
     --step-4 it becomes a wall of type instead of a masthead. */
  --step--1: clamp(0.78rem, 0.75rem + 0.14vw, 0.86rem);
  --step-0: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --step-1: clamp(1.125rem, 1.04rem + 0.4vw, 1.35rem);
  --step-2: clamp(1.5rem, 1.3rem + 1vw, 2.25rem);
  --step-3: clamp(1.95rem, 1.42rem + 2.35vw, 3.35rem);
  --step-4: clamp(2.5rem, 1.9rem + 3vw, 4.5rem);

  --gutter: clamp(1.25rem, 5vw, 4rem);
  --section-y: clamp(4.5rem, 10vw, 9rem);
  --rail: minmax(0, 17rem);
  --body: minmax(0, 46rem);
  --col-gap: clamp(2rem, 4vw, 4.5rem);

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);

  color-scheme: dark;
}

/* ---------------------------------------------------------------------
   2. Reset
   ------------------------------------------------------------------ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* Guard against any single element pushing the page sideways. `clip`
     rather than `hidden` so no scroll container is created. */
  overflow-x: clip;
  -webkit-text-size-adjust: 100%;
}

body,
h1,
h2,
h3,
p,
ol,
ul,
figure {
  margin: 0;
}

ol,
ul {
  padding: 0;
}

img {
  max-width: 100%;
  height: auto;
}

/* app.js sets form.hidden = true on success. Several elements below are
   display:grid, which would otherwise defeat the hidden attribute. */
[hidden] {
  display: none !important;
}

/* ---------------------------------------------------------------------
   3. Ground, patina and grain
   ------------------------------------------------------------------ */

body {
  background-color: var(--ground);
  color: var(--text);
  font-family: var(--prose);
  font-size: var(--step-0);
  font-weight: 380;
  line-height: 1.62;
  overflow-wrap: break-word;
}

/* Patina. Viewport-fixed so the wash never stretches down a long
   document; three low-alpha radials, no single flat fill. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(58% 44% at 78% 8%, var(--patina-1), transparent 68%),
    radial-gradient(46% 38% at 8% 58%, var(--patina-2), transparent 70%),
    radial-gradient(70% 50% at 50% 108%, rgba(46, 111, 98, 0.13), transparent 72%);
}

/* Grain. 1px engraved hatch across the whole page at an alpha that is
   felt rather than seen. Sits above content; must not eat clicks. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    115deg,
    rgba(220, 230, 225, 0.018) 0 1px,
    transparent 1px 3px
  );
}

::selection {
  background: var(--brass);
  color: var(--ground);
}

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

/* ---------------------------------------------------------------------
   4. Type
   ------------------------------------------------------------------ */

h1,
h2 {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: 0.01em;
  text-wrap: balance;
}

h1 {
  font-size: var(--step-3);
  line-height: 1.09;
  /* Didone at display size needs the tracking pulled back in. */
  letter-spacing: -0.012em;
  text-wrap: pretty;
}

h2 {
  font-size: var(--step-2);
  line-height: 1.14;
}

h3,
label,
button,
input,
textarea,
.stages li::before {
  font-family: var(--mono);
}

p + p {
  margin-top: 1.1em;
}

/* ---------------------------------------------------------------------
   5. Masthead
   ------------------------------------------------------------------ */

#masthead {
  position: relative;
  isolation: isolate;
  overflow: hidden; /* the dial bleeds past the right edge */
  display: grid;
  grid-template-columns: minmax(0, 72rem);
  justify-content: center;
  align-content: center;
  gap: clamp(1.6rem, 3vw, 2.4rem);
  min-height: 100vh;
  min-height: min(100svh, 58rem);
  padding: clamp(5rem, 13vh, 9rem) var(--gutter) clamp(4rem, 9vh, 7rem);
  border-bottom: 1px solid var(--rule);
  background:
    radial-gradient(60% 50% at 50% 0%, var(--patina-1), transparent 70%),
    radial-gradient(40% 40% at 15% 85%, var(--patina-2), transparent 70%),
    linear-gradient(180deg, var(--ground-lift), var(--ground) 70%);
}

/* Fine engraved grain, local to the masthead. Low alpha on purpose. */
#masthead::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    115deg,
    rgba(220, 230, 225, 0.035) 0 1px,
    transparent 1px 3px
  );
}

#masthead > h1,
#masthead > .lede {
  position: relative;
  z-index: 1;
}

#masthead > h1 {
  /* ~34-38 characters a line: four or five lines of instrument, not a
     paragraph set in display type. Also the measure that keeps the
     headline clear of the dial's pointer at the narrow end of the
     two-column masthead. */
  max-width: 16em;
}

#masthead > .lede {
  max-width: 44ch;
  font-size: var(--step-1);
  line-height: 1.55;
  color: var(--text-dim);
}

#masthead > .lede::before {
  content: "";
  display: block;
  width: 3.5rem;
  height: 1px;
  margin-bottom: clamp(1.1rem, 2vw, 1.6rem);
  background: var(--verdigris);
}

/* ---------------------------------------------------------------------
   6. The dial
   ---------------------------------------------------------------------
   Seven hairline elements. Above 64em the instrument is anchored off the
   right edge, cropped by the frame rather than centred like a medallion,
   and the headline crosses only its outermost, faintest rings — never the
   brass pointer. Below 64em there is no room for that and the two are
   stacked instead; see section 16.

   --len is that element's path length in viewBox user units, rounded up
   about 1%: it is both the dash and the starting offset, so the element
   begins fully retracted and finishes closed.

   `vector-effect: non-scaling-stroke` is deliberately NOT used here, and
   must not be added. It resolves all stroke geometry — dasharray and
   dashoffset included — in screen space, while every --len below is in
   user units. The two disagree by the viewBox scale (up to 1.227x), which
   would leave the bezel visibly open in its final state above ~980px wide
   and invert the retracted start state into disconnected inked fragments.
   Without it, path and dash share one coordinate space and the scale
   cancels: strokes render between 0.62px and 1.23px across the range,
   which is what a hairline should do anyway.
   ------------------------------------------------------------------ */

.dial {
  position: absolute;
  z-index: 0;
  top: 50%;
  /* Flat bleed, not a vw fraction. The brass pointer must clear the right
     edge of the headline at every width this rule covers, and the headline
     grows faster than a proportional bleed does: at 1024px a -13vw bleed
     put the pointer 117px inside the h1. 16rem clears it from 64em up. */
  right: -16rem;
  width: min(46rem, 62vw);
  height: auto;
  aspect-ratio: 1;
  pointer-events: none;
  transform: translateY(-50%);
}

.dial > * {
  fill: none;
  stroke: var(--rule);
  stroke-width: 1;
  stroke-dasharray: var(--len);
  stroke-dashoffset: var(--len);
  /* Longhands, not the shorthand: --delay and --dur are inherited custom
     properties, and one bad value in the shorthand invalidates the whole
     declaration at computed-value time, giving `animation: none` and an
     element frozen in its retracted, invisible start state. As longhands a
     bad value costs only that one property. */
  animation-name: draw;
  animation-duration: var(--dur, 900ms);
  animation-delay: var(--delay, 0ms);
  animation-timing-function: var(--ease-out);
  animation-fill-mode: both;
}

/* Outer bezel */
.dial > :nth-child(1) {
  --len: 1800;
  --dur: 1000ms;
  --delay: 0ms;
}

/* Second bezel ring */
.dial > :nth-child(2) {
  --len: 1500;
  --dur: 900ms;
  --delay: 80ms;
  stroke: var(--verdigris-line);
}

/* The 270-degree sweep — the structural line of the whole composition */
.dial > :nth-child(3) {
  --len: 900;
  --dur: 900ms;
  --delay: 170ms;
  stroke: var(--verdigris-line-hi);
  stroke-width: 1.25;
}

/* Twelve index ticks. One path, twelve subpaths: renderers restart the
   dash pattern per subpath, so --len is set above one tick's length and
   a paired fade keeps the timing honest whichever way it resolves. */
.dial .ticks {
  --len: 240;
  --dur: 560ms;
  --delay: 360ms;
  stroke: rgba(220, 230, 225, 0.30);
  animation-name: draw, fade;
  animation-duration: var(--dur), var(--dur);
  animation-delay: var(--delay), var(--delay);
  animation-timing-function: var(--ease-out), linear;
  animation-fill-mode: both, both;
}

/* Inner register */
.dial > :nth-child(5) {
  --len: 890;
  --dur: 820ms;
  --delay: 250ms;
}

/* The pointer. The only brass on the page above the fold. */
.dial .lead {
  --len: 200;
  --dur: 520ms;
  --delay: 620ms;
  stroke: var(--brass);
  stroke-width: 2;
  stroke-linecap: round;
  filter: drop-shadow(0 0 7px var(--brass-glow));
}

/* Pivot */
.dial > :nth-child(7) {
  --len: 285;
  --dur: 620ms;
  --delay: 330ms;
  stroke: rgba(62, 140, 122, 0.45);
}

/* ---------------------------------------------------------------------
   7. Section frame
   ---------------------------------------------------------------------
   A two-track ledger: the heading sits alone in a narrow left rail, the
   argument runs in a measured column beside it. Deliberately not a
   centred stack, and deliberately not a grid of cards.
   ------------------------------------------------------------------ */

section:not(#masthead) {
  display: grid;
  grid-template-columns: var(--body);
  justify-content: center;
  align-content: start;
  gap: clamp(1.4rem, 3vw, 2.2rem) var(--col-gap);
  padding: var(--section-y) var(--gutter);
}

section:not(#masthead) > h2 {
  color: var(--text);
}

section:not(#masthead) > h2::after {
  content: "";
  display: block;
  width: 2.75rem;
  height: 1px;
  margin-top: clamp(0.9rem, 2vw, 1.3rem);
  background: var(--verdigris);
}

section p,
section li {
  max-width: 66ch;
}

/* Direct children of the section grid are spaced by row-gap, not margins. */
section:not(#masthead) > p + p {
  margin-top: 0;
}

@media (min-width: 60em) {
  section:not(#masthead) {
    grid-template-columns: var(--rail) var(--body);
  }

  /* Row 1 only, never a span: spanning implicit rows would insert a
     row-gap for every empty row underneath the heading. */
  section:not(#masthead) > h2 {
    grid-column: 1;
    grid-row: 1;
    align-self: start;
  }

  section:not(#masthead) > :not(h2) {
    grid-column: 2;
  }
}

/* ---------------------------------------------------------------------
   8. The default this exists to fix
   ------------------------------------------------------------------ */

#default > p {
  font-size: var(--step-1);
  line-height: 1.58;
}

/* ---------------------------------------------------------------------
   9. Method — five stages
   ------------------------------------------------------------------ */

#method {
  background-image: radial-gradient(
    38% 44% at 4% 40%,
    rgba(46, 111, 98, 0.10),
    transparent 70%
  );
}

.stages {
  list-style: none;
  counter-reset: stage;
}

.stages li {
  counter-increment: stage;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.55rem;
  max-width: none;
  padding-block: clamp(1.6rem, 3vw, 2.4rem);
  border-top: 1px solid var(--rule);
}

.stages li:last-child {
  border-bottom: 1px solid var(--rule);
}

.stages li::before {
  content: counter(stage, decimal-leading-zero);
  font-size: var(--step--1);
  font-weight: 400;
  letter-spacing: 0.1em;
  line-height: 1;
  color: var(--text-dim);
}

.stages h3 {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--verdigris);
}

.stages p {
  max-width: 62ch;
  color: var(--text);
}

@media (min-width: 40em) {
  .stages li {
    grid-template-columns: 4.5rem minmax(0, 1fr);
    column-gap: clamp(1rem, 2vw, 2rem);
    row-gap: 0.7rem;
  }

  .stages li::before {
    grid-column: 1;
    grid-row: 1 / span 2;
    padding-top: 0.35em;
  }

  .stages h3,
  .stages p {
    grid-column: 2;
  }
}

/* ---------------------------------------------------------------------
   10. Deliverables — a ledger, not cards
   ------------------------------------------------------------------ */

#deliverables ul {
  list-style: none;
}

#deliverables li {
  display: grid;
  grid-template-columns: 1.9rem minmax(0, 1fr);
  align-items: start;
  max-width: 68ch;
  padding-block: clamp(1.05rem, 2vw, 1.4rem);
  border-top: 1px solid var(--rule);
}

#deliverables li:last-child {
  border-bottom: 1px solid var(--rule);
}

#deliverables li::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  margin-top: 0.62em;
  border: 1px solid var(--verdigris);
  transform: rotate(45deg);
}

/* ---------------------------------------------------------------------
   11. What we don't claim — the inset plate
   ------------------------------------------------------------------ */

#limits {
  background-color: var(--ground-lift);
  border-block: 1px solid var(--rule);
  box-shadow: inset 0 1px 0 var(--rule-soft);
}

#limits p {
  color: var(--text-dim);
}

#limits p:first-of-type {
  color: var(--text);
}

/* ---------------------------------------------------------------------
   12. Contact
   ---------------------------------------------------------------------
   Concentric engraved rings rise behind the form, echoing the dial.
   ------------------------------------------------------------------ */

/* No overflow clipping here: Turnstile's challenge widget expands
   its own box and must never be cut off. */
#contact {
  position: relative;
  background-image:
    repeating-radial-gradient(
      circle at 50% 132%,
      var(--rule-soft) 0 1px,
      transparent 1px 46px
    ),
    radial-gradient(52% 42% at 50% 128%, rgba(62, 140, 122, 0.14), transparent 70%);
}

#contact-form {
  position: relative;
  display: grid;
  max-width: 34rem;
}

#contact-form > label:first-of-type {
  margin-top: 0.5rem;
}

#contact-form label {
  display: block;
  margin-top: 1.9rem;
  margin-bottom: 0.55rem;
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* No alpha on the optional marker: at this size it fell to 3.8:1. It is
   distinguished by case and tracking, not by being harder to read. */
#contact-form label span {
  text-transform: none;
  letter-spacing: 0.06em;
}

#contact-form input,
#contact-form textarea {
  width: 100%;
  max-width: 100%;
  padding: 0.72rem 0.85rem;
  /* 16px floor: anything smaller and mobile Safari zooms the page on
     focus, which throws the layout for the length of the enquiry. */
  font-size: 1rem;
  letter-spacing: 0.02em;
  line-height: 1.55;
  color: var(--text);
  background-color: var(--well);
  /* WCAG 1.4.11 wants 3:1 for the boundary of a UI component, and this is
     the only conversion point on the site. --rule reaches 1.41:1 against
     the ground; --verdigris-d reaches 3.17:1. The well stays dark so the
     field still reads as a recess — the border, not the fill, carries the
     boundary. */
  border: 1px solid var(--verdigris-d);
  border-radius: 0;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35);
  transition:
    border-color 160ms var(--ease-out),
    background-color 160ms var(--ease-out);
}

#contact-form textarea {
  resize: vertical;
  min-height: 9rem;
}

#contact-form input:hover,
#contact-form textarea:hover {
  border-color: var(--verdigris); /* 4.66:1 */
}

#contact-form input:focus-visible,
#contact-form textarea:focus-visible {
  border-color: var(--brass);
  outline: 1px solid var(--brass);
  outline-offset: 1px;
}

/* Chrome paints autofilled fields pale blue; on this ground that reads as
   a bug. Hold the well colour and the text colour. */
#contact-form input:-webkit-autofill,
#contact-form input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--text);
  -webkit-box-shadow: 0 0 0 1000px var(--ground-lift) inset;
  caret-color: var(--text);
}

.cf-turnstile {
  margin-top: 2rem;
  min-height: 65px;
}

#contact-form button {
  justify-self: start;
  margin-top: 1.9rem;
  padding: 0.85rem 2.2rem;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--brass-hot);
  background-color: transparent;
  border: 1px solid var(--brass);
  border-radius: 0;
  cursor: pointer;
  transition:
    color 180ms var(--ease-out),
    background-color 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out);
}

#contact-form button:hover:not(:disabled) {
  color: var(--ground);
  background-color: var(--brass-hot);
  box-shadow: 0 0 22px rgba(192, 138, 62, 0.22);
}

#contact-form button:active:not(:disabled) {
  background-color: var(--brass);
}

#contact-form button:disabled {
  color: var(--text-dim);
  border-color: var(--rule);
  cursor: progress;
}

/* Deliberately a sibling of the form, not a child of it: app.js sets
   form.hidden = true on success, and a status paragraph inside the form
   would be hidden along with it — the visitor would watch the form vanish
   with no confirmation, and nothing would reach assistive technology
   either. Kept in the DOM and rendered at all times, since it is the live
   region; spacing comes from the section's own row-gap, so an empty one
   adds nothing to look at. */
#form-status {
  max-width: 34rem;
  margin-top: 0;
  font-family: var(--mono);
  font-size: var(--step--1);
  line-height: 1.7;
  letter-spacing: 0.03em;
  color: var(--brass-hot); /* 9.66:1 — something still needs the visitor */
}

/* Success and failure must not look identical. app.js exposes no state
   class, but it does hide the form on success and only on success, so the
   two outcomes are already distinguishable from the markup: every error
   path leaves the form standing. Brass reads as "your turn"; verdigris
   (4.66:1) reads as "done, nothing further". */
#contact-form[hidden] + #form-status {
  color: var(--verdigris);
}

/* ---------------------------------------------------------------------
   13. Honeypot
   ---------------------------------------------------------------------
   The endpoint silently discards any submission where `website` is
   non-empty. If a human can see this field they will fill it in honestly
   and their enquiry will be thrown away while the page tells them it
   succeeded. So it is removed from the flow, parked far off-canvas,
   clipped to nothing, made fully transparent and made unclickable — five
   independent reasons it can never be seen or hit. It is already
   tabindex="-1" and aria-hidden in the markup, so keyboard and screen
   reader users cannot reach it either.
   Off-canvas to the left does not create a scrollable area in LTR.

   Deliberately NOT `display: none`: bots skip fields hidden that way, and a
   honeypot they skip catches nobody. Do not "simplify" this to display:none
   — it would quietly disable the trap. The axe `aria-hidden-focus` finding
   on the wrapper is an accepted, recorded trade-off, not an oversight.
   ------------------------------------------------------------------ */

.trap {
  position: absolute !important;
  left: -9999px !important;
  top: auto !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
  clip-path: inset(50%) !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* ---------------------------------------------------------------------
   14. Motion — one orchestrated load, CSS only
   ---------------------------------------------------------------------
   The dial draws from the bezel inward, the ticks strike, the pointer
   lands last; the headline, lede and five stages rise underneath on a
   65ms stagger. Everything is settled inside ~1.2s and nothing loops.
   ------------------------------------------------------------------ */

@keyframes draw {
  to {
    stroke-dashoffset: 0;
  }
}

@keyframes fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

#masthead > h1,
#masthead > .lede,
.stages li {
  opacity: 0;
  /* Longhands for the same reason as the dial: a bad --delay must not be
     able to cancel the animation and strand the headline at opacity 0. */
  animation-name: rise;
  animation-duration: 640ms;
  animation-delay: var(--delay, 0ms);
  animation-timing-function: var(--ease-out);
  animation-fill-mode: forwards;
}

#masthead > h1 { --delay: 140ms; }
#masthead > .lede { --delay: 250ms; }
.stages li:nth-child(1) { --delay: 320ms; }
.stages li:nth-child(2) { --delay: 385ms; }
.stages li:nth-child(3) { --delay: 450ms; }
.stages li:nth-child(4) { --delay: 515ms; }
.stages li:nth-child(5) { --delay: 580ms; }

/* ---------------------------------------------------------------------
   15. Reduced motion
   ---------------------------------------------------------------------
   Not merely shorter: the reveal above starts at opacity 0 and the dial
   starts fully retracted, so collapsing durations alone would leave the
   headline, the lede, the five stages and the whole instrument invisible
   for anyone with the preference set. Every animated element is put back
   into its finished state explicitly.
   ------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }

  /* Final state of `rise`. */
  #masthead > h1,
  #masthead > .lede,
  .stages li {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  /* Final state of `draw` and `fade`, for all seven dial elements. */
  .dial > * {
    animation: none !important;
    stroke-dashoffset: 0 !important;
    opacity: 1 !important;
  }
}

/* ---------------------------------------------------------------------
   16. Narrow and small screens
   ---------------------------------------------------------------------
   Two separate concerns, two separate queries.

   (a) Below 64em the masthead has no room to set the headline beside the
   instrument, so the two are stacked instead of overlapped: type anchored
   to the top of the section, the dial anchored past the bottom-right
   corner, arcs rising into the space under the lede. This is the same
   cropped-by-the-frame idea rotated, not a medallion behind the type — at
   768px the previous rule centred the entire instrument, pivot and brass
   pointer included, behind a five-line display headline.

   (b) Below 40em the dial additionally simplifies. It never disappears.
   ------------------------------------------------------------------ */

@media (max-width: 63.99em) {
  #masthead {
    align-content: start;
  }

  .dial {
    top: auto;
    /* Proportional at the narrow end so the instrument stays substantially
       on screen at 360px, capped in rem at the wide end so it does not
       walk off the corner by 1023px. */
    right: max(-13rem, -22vw);
    bottom: max(-15rem, -30vw);
    width: min(34rem, 104vw);
    transform: none;
  }

  /* Strokes scale with the dial now that non-scaling-stroke is gone, and
     the scale bottoms out around 0.62 here; a slightly heavier user-unit
     width holds the rendered hairline near 1px. The sweep, the pointer and
     the pivot set their own widths at higher specificity. */
  .dial > * {
    stroke-width: 1.15;
  }
}

@media (max-width: 39.99em) {
  /* Drop the second bezel and the index ticks: at this size they collapse
     into noise. Bezel, sweep, register, pointer and pivot remain. */
  .dial > :nth-child(2),
  .dial .ticks {
    display: none;
  }

  #masthead > h1 {
    max-width: none;
  }
}

/* ---------------------------------------------------------------------
   17. Preference refinements
   ------------------------------------------------------------------ */

@media (prefers-contrast: more) {
  :root {
    --rule: rgba(220, 230, 225, 0.34);
    --text-dim: #B6C9C2;
  }

  #contact-form input,
  #contact-form textarea {
    border-color: var(--verdigris); /* 3.17:1 -> 4.66:1 */
  }

  body::after {
    display: none;
  }
}
