/*
  §2 "undatable institutional".
  What dates a web page is almost entirely ornament, so there is none here: no gradient, no shadow,
  no rounded corner, no glass, no animation, no transition. Verification check 7 asserts that
  mechanically — grep this file for `gradient|shadow|radius` and the answer must stay zero.

  Fixed light "paper" appearance by design. NO dark mode and no toggle: a theme toggle is itself a
  2020s signal, and the fixed paper buys the hard contrast §2 wants against the terminal —
  the institution is paper, the machine is phosphor.

  Hand-authored rather than built on Designframe. §2 asks for "Designframe for layout primitives
  only" AND "no build step, plain HTML + one stylesheet"; those pull against each other, because
  using DF means shipping DF's compiled CSS. Sixty lines of hand-authored rules honour the stronger
  of the two constraints and keep the emitted surface auditable by eye. Flagged for Mike, not
  resolved silently.
*/

:root {
  --paper: #faf9f5;
  --ink: #1c1b18;
  --muted: #6b6862;
  --rule: #ceccc4;
  --measure: 68ch;
}

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

body {
  margin: 0;
  padding: 4rem 1.5rem 6rem;
  background: var(--paper);
  color: var(--ink);
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

header, main, footer { max-width: var(--measure); margin-inline: auto; }

/* ==========================================================================
   ENTRY PAGE (apex)
   Futurism by precision, not decoration: a label/value record, hairline rules, severe alignment,
   and a large empty field around the seal. Instrument documentation, not a console. One family
   throughout — the technical register comes from size, tracking and case, never from a second
   typeface, because monospace-as-technical-signal is itself heavily era-coded.
   ========================================================================== */

/*
  The entry page owns the whole viewport, so it must not inherit the document padding that the
  register needs. Scoped with :has() rather than a body class, so the page's own structure decides
  it and no one has to remember to add an attribute. Without this the document runs 160px taller
  than the viewport and the "centred" seal is centred in something that scrolls.
*/
/*
  `touch-action: none` so tracing a circle with a finger does not scroll the page out from under
  the gesture. Safe here specifically because this page has no scrollable overflow (measured: doc
  height == viewport height at both 1440 and 375) — it would be hostile on any page that scrolls.
*/
body:has(.core) { padding: 0; touch-action: none; }

/*
  The mark once it has been unlocked. `display: block` matters: the anchor takes the seal's place
  as the middle child of a three-row grid, and an inline element there would shift the mark off
  the true centre the layout was measured at (0px offset).
  No visual treatment — whether an unlocked mark should LOOK different is Arc 2's question, and
  answering it here would pre-empt a design decision with a default.
*/
.mark-link { display: block; line-height: 0; }

/*
  Calibration readout — only present with ?calibrate=1, and the instrument the whole of Arc 1
  exists to produce. Deliberately plain: it is a measuring tool, not part of the fiction.
*/
.calibrate {
  position: fixed;
  left: 0;
  right: 0;
  top: 1.5rem;
  margin: 0;
  text-align: center;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: var(--muted);
}

/*
  Four hairline corner brackets, fixed to the viewport. Each span carries exactly two borders, so
  the corner is implied rather than drawn — a closed rectangle would read as a border, and a border
  reads as a document. Brackets read as an instrument framing something.
*/
.frame span {
  position: fixed;
  width: 26px;
  height: 26px;
  border: 0 solid var(--rule);
  pointer-events: none;
}

.frame span:nth-child(1) { top: 1.75rem; left: 1.75rem; border-top-width: 1px; border-left-width: 1px; }
.frame span:nth-child(2) { top: 1.75rem; right: 1.75rem; border-top-width: 1px; border-right-width: 1px; }
.frame span:nth-child(3) { bottom: 1.75rem; left: 1.75rem; border-bottom-width: 1px; border-left-width: 1px; }
.frame span:nth-child(4) { bottom: 1.75rem; right: 1.75rem; border-bottom-width: 1px; border-right-width: 1px; }

.wordmark {
  /* 3.25rem matches .motto's top margin exactly — equal gaps either side of the mark. */
  margin: 0 0 3.25rem;
  font-size: 0.75rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--muted);
}

/*
  The ring is an SVG <circle>, deliberately not a CSS `border-radius: 50%`. Check 7 asserts zero
  radius declarations in this file and cannot distinguish a structural circle from an ornamental
  rounded corner — so the mark is drawn as artwork, which is the correct tool regardless.
  The device is the TYPOGRAPHIC Ψ: the wordmark and the seal must be one letterform.
*/
/*
  Sized up once the charter paragraph came out — the mark is the page now, not an ornament above
  the copy. The SVG is a 240 viewBox, so the glyph and ring scale with it and nothing needs
  re-tuning at a new size.
*/
.seal { display: block; width: 290px; height: 290px; color: var(--ink); }

.seal-glyph {
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  font-size: 128px;
  fill: currentColor;
}

/* --- the loops -----------------------------------------------------------
   Two circles, not one. The base sits faint; the seam is dashed and its offset travels. Where the
   gap passes, only the base shows through, so the ring reads as THINNING rather than as a hole
   opening in it — the seal losing coherence at one point, continuously, and getting it back.
   Circumference is 2πr = 2π(110) = 691.15, which is where the dash numbers come from.
   Slow on purpose: perceptible only if you rest on it. Motion that asks to be watched is
   interface; motion you catch out of the corner of your eye is weather.                        */

.seal-ring-base { opacity: 0.22; }

/*
  The warp. The mark distorts toward whatever the pointer is doing — ANY movement, not just
  circling.

  ⛔ Driven by pointer POSITION, never by turns. A charge ring lived here and was removed on Mike's
  ruling: "i dont want the user to see a clear progress towards something." It worked, which was
  the problem — a legible arc completing at three turns makes the secret a task, and a distortion
  that grew with progress would be the same progress bar in a costume. Nothing here is countable.

  Non-uniform scale is what makes it read as SPACE bending rather than the mark sliding about: the
  circle stops being a circle, stretched along the axis the pointer sits on. Everything is scaled
  by --activity, so the mark settles when the pointer stops.

  Bare var() substitutions with units already applied — entry.js resolves them. calc() on a custom
  property does not reduce at computed-value time; that is measured, not folklore.
*/
/*
  ⛔ A CSS transform lived here and was REMOVED. It translated and scaled the whole mark as one
  rigid object — the mark SLID, space did not bend — and no amount of tuning bridges that gap,
  because a transform is by definition affine and applies to the element as a unit.

  The displacement filter is the actual mechanism: every pixel moves by a different amount, taken
  from a turbulence field. Permitted by J1's gate exception, which bans the filter FUNCTIONS that
  are ornament (drop-shadow, blur) while allowing an SVG reference, and is enforced by
  foundation-tests/ornament-gate.test.js rather than by anybody remembering it.
*/
/*
  The Ψ is an SVG <text> element, so by default it behaves like text: I-beam cursor, and it
  drag-selects. Both are wrong for a mark whose entire purpose is being swept over — the caret
  announces "this is a string" at precisely the moment the reader should be feeling a surface.
*/
.seal {
  cursor: default;
  user-select: none;
  -webkit-user-select: none;
}

/*
  The WebGL field sits exactly where the mark does. `data-field="on"` is set by entry.js ONLY once
  a renderer actually initialises — so if WebGL is missing, or the shader fails to compile, the SVG
  is never hidden and the page is exactly what it is today. The effect is additive; its absence
  costs nothing.
*/
.field {
  display: block;
  width: 290px;
  height: 290px;
  pointer-events: none;
}

:root[data-field="on"] .seal {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/* Reduced motion keeps the still SVG and drops the canvas entirely. */
@media (prefers-reduced-motion: reduce) {
  .field { display: none; }
  :root[data-field="on"] .seal {
    position: static;
    width: 290px;
    height: 290px;
    overflow: visible;
    clip-path: none;
  }
}

/*
  The filter is applied to the WARPED LAYER only (see index.html), never to the whole seal — that
  was the global-warp mistake. This rule exists so the reduced-motion override below has something
  to switch off at the element the reader actually sees.
*/

/*
  Reduced motion pins the warp off. It lives HERE rather than behind a matchMedia in entry.js on
  purpose: the gesture path must stay free of motion conditionals so the census proving the UNLOCK
  is not motion-gated (0 hits across gesture.js and entry.js) keeps holding.
*/
@media (prefers-reduced-motion: reduce) {
  /*
    Targets the WARPED LAYER, not `.seal`. The filter moved onto the layer when the mark was split
    in two, and a `.seal { filter: none }` left behind would override nothing at all — a dead
    accessibility guard that still reads as present.
  */
  .seal-warped { filter: none; }
}

/*
  An unlocked mark is a control, so it takes the hand cursor.

  ⛔ The descendant selector is load-bearing. `.seal { cursor: default }` (which kills the I-beam
  the SVG <text> would otherwise give) sits on the INNER element, so it wins on specificity once
  the seal is wrapped in the anchor — leaving an unlocked, clickable mark showing a plain arrow.
*/
.mark-link,
.mark-link .seal { cursor: pointer; }

.seal-ring-seam {
  stroke-dasharray: 620 71;
  animation: seal-seam 48s linear infinite;
}

@keyframes seal-seam { to { stroke-dashoffset: -691.15; } }

.seal-glyph { animation: seal-ink 14s ease-in-out infinite; }

@keyframes seal-ink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.86; }
}

/*
  Non-negotiable: looping motion must be switchable off at the OS level. Resetting the dasharray
  too, not just the animation — a stopped seam would otherwise freeze as a permanent visible gap,
  which is a worse artifact than the animation it replaces.
*/
@media (prefers-reduced-motion: reduce) {
  .seal-ring-seam { animation: none; stroke-dasharray: none; }
  .seal-glyph { animation: none; opacity: 1; }
}

/* --- centred core ---------------------------------------------------------
   Everything on one vertical axis through the seal. The science-fiction register comes from
   framing and spacing, never from gloss: hairline corner brackets, wide tracking, and a lot of
   nothing. A frame implies an instrument reading something.                                   */

/*
  Three rows — 1fr / seal / 1fr — NOT a centred flex column. Centring the stack put the seal ~80px
  high, because the motto and link below outweigh the wordmark above. With equal fr rows
  either side, the SEAL's centre is the viewport's centre by construction, and it stays that way
  however the copy changes. The wordmark hangs from the bottom of the upper row and the group sits
  at the top of the lower one, so both read as orbiting the mark rather than stacked against it.
*/
.core {
  max-width: 34rem;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  justify-items: center;
  text-align: center;
}

.core > .wordmark { align-self: end; }
.core > .motto { align-self: start; }

/*
  The gaps above and below the mark are deliberately EQUAL. The seal is pinned to true centre by
  the grid, but unequal margins either side make a geometrically-centred mark read as off-centre —
  optical centring is about the gaps, not the coordinates.
*/
.motto {
  margin: 3.25rem 0 0;
  font-size: 1rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

/*
  Fixed to the bottom frame line, level with the corner brackets. Those occupy only the corners, so
  a centred link between them cannot collide. Taking the link out of the centred group is what lets
  the mark's centre and the composition's centre finally coincide.
*/
.onward {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 1.75rem;
  text-align: center;
  font-size: 0.9375rem;
}

.onward a,
.back a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  padding-bottom: 2px;
}

.onward a:hover,
.back a:hover { border-bottom-color: var(--ink); }

/* Back link — register subpage only. */
.back { margin-top: 3.5rem; padding-top: 1.5rem; border-top: 1px solid var(--rule); font-size: 0.9375rem; }

@media (max-width: 620px) {
  .seal { width: 200px; height: 200px; }
  /* Equal gaps either side of the mark hold at every width, so both values move together. */
  .wordmark { margin-bottom: 2.25rem; letter-spacing: 0.24em; }
  .motto { margin-top: 2.25rem; font-size: 0.8125rem; letter-spacing: 0.14em; }
  .frame span { width: 18px; height: 18px; top: auto; }
  .frame span:nth-child(1), .frame span:nth-child(2) { top: 1rem; }
  .frame span:nth-child(3), .frame span:nth-child(4) { bottom: 1rem; }
  .frame span:nth-child(1), .frame span:nth-child(3) { left: 1rem; }
  .frame span:nth-child(2), .frame span:nth-child(4) { right: 1rem; }
}

/* Masthead ---------------------------------------------------------------- */

.mark {
  margin: 0;
  font-size: 2.75rem;
  line-height: 1;
  font-weight: 400;
}

h1 {
  margin: 1rem 0 0;
  font-size: 1.375rem;
  font-weight: 400;
  letter-spacing: 0.02em;
}

header { padding-bottom: 2.5rem; border-bottom: 1px solid var(--rule); }

/* Statement --------------------------------------------------------------- */

/* Register ---------------------------------------------------------------- */

h2 {
  margin: 0 0 0.5rem;
  font-size: 1rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.note { margin: 0 0 1.75rem; color: var(--muted); font-size: 0.9375rem; }

table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }

thead th {
  padding: 0 0.75rem 0.5rem 0;
  border-bottom: 1px solid var(--ink);
  font-weight: 400;
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: left;
  color: var(--muted);
}

tbody th, tbody td {
  padding: 0.7rem 0.75rem 0.7rem 0;
  border-bottom: 1px solid var(--rule);
  text-align: left;
  vertical-align: top;
  font-weight: 400;
}

tbody th { white-space: nowrap; color: var(--muted); }

/*
  Addresses must never break across lines. Punycode carries a double hyphen (`xn--`), and a hyphen is
  a legal break opportunity, so an unprotected address wraps as `alter.xn-` / `-9xa.foundation`.
  These strings exist to be transcribed into a URL bar by hand; a break there is a transcription
  hazard, not a cosmetic one.
*/
td[data-label="Address"] { white-space: nowrap; }

s { color: var(--muted); }
.empty { color: var(--rule); }

/* Footer ------------------------------------------------------------------ */

footer { margin-top: 4rem; padding-top: 1.5rem; border-top: 1px solid var(--rule); }
footer p { margin: 0; color: var(--muted); font-size: 0.9375rem; }

/* Narrow ------------------------------------------------------------------- */
/*
  Verification check 6: the register must not scroll horizontally at 375px. Four columns cannot hold
  a readable measure at that width, so below 620px each entry becomes a stacked record with its
  field names restated from data-label — which is how these things are set in print anyway.
*/

@media (max-width: 620px) {
  body { padding: 3rem 1.25rem 4rem; }

  thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }

  tbody tr { display: block; padding: 1rem 0; border-bottom: 1px solid var(--rule); }
  tbody th, tbody td { display: block; padding: 0; border: 0; }
  tbody th { margin-bottom: 0.25rem; }

  tbody td::before {
    content: attr(data-label) " — ";
    color: var(--muted);
    font-size: 0.8125rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }
}
