/* ═══════════════════════════════════════════════════════════════════════════
   THE LOOPMMT WEBSITE — SHELL · v1
   Loop MMT™ · CC BY-NC 4.0

   The site's chrome + block set. Layer 1 in the composition triple:

     Layer 0. tokens.css               ← the DNA (palette, type, rhythm, layout)
     Layer 1. shell.css (this file)    ← Frame, Porch, Room, Corpus Frame,
                                         Honest Badge, Marker
     Layer 2. component-specific CSS   ← per-artifact styling

   Composition rule: every page is the Frame containing one of
   Porch / Corridor / Room / Corpus Frame. That's the whole grammar.

   The hard rule: every colour reads var(--*) from tokens.css. This file
   carries NO hex literals in rules — the exceptions are in comments, never
   in declarations.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ 1. Reset (minimal — just the things we can't live without) ═══ */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; }
img, svg { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }


/* ═══ 2. Base typography (reads from tokens.css) ═══ */

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--size-body);
  line-height: var(--lh-body);
  font-weight: var(--weight-body);
  /* Anti-aliasing for the display face; the body face is fine as default. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3 {
  font-family: var(--font-display);
  color: var(--ink);
  margin: 0 0 var(--gap) 0;
  font-weight: var(--weight-display);
  letter-spacing: var(--track-display);
}

h1 { font-size: var(--size-display);   line-height: var(--lh-display);  }
h2 { font-size: var(--size-headline);  line-height: var(--lh-headline); font-weight: var(--weight-headline); }
h3 {
  font-family: var(--font-mono);
  font-size: var(--size-label);
  line-height: var(--lh-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--muted);
  margin: var(--gap-wide) 0 var(--gap-tight) 0;
  font-weight: 500;
}

p { margin: 0 0 var(--gap) 0; }

.lead {
  font-size: var(--size-lead);
  line-height: var(--lh-lead);
  color: var(--ink);
  margin-bottom: var(--gap-wide);
}

.label {
  font-family: var(--font-mono);
  font-size: var(--size-label);
  line-height: var(--lh-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--muted);
}

.faint {
  /* WCAG note (contrast pass): --faint on --paper is 3.31:1 — passes
     WCAG 2.1 AA LARGE-text (3:1, ≥24px or 19px-bold) but NOT small-text (4.5:1).
     Reserve .faint for large-text or non-text uses; for small-text captions on
     paper, use .muted (color --muted passes 6.87:1). */
  color: var(--faint);
}

.muted {
  /* Small-text-safe on --paper (6.87:1 AA pass, WCAG 2.1 §1.4.3). Use for
     footer metadata, small captions, secondary chrome text. */
  color: var(--muted);
}

.mono {
  font-family: var(--font-mono);
  font-size: var(--size-code);
  line-height: var(--lh-code);
}


/* ═══ 3. The Frame — site-wide chrome ═══
   Owns the top 64px band + the natural-height footer. Everything between
   is the contained block's (Porch / Room / Corpus Frame). J1 test:
   top bar STICKS on scroll; footer sits at NATURAL bottom (not fixed).
   J5 test: footer carries five elements — disclosure, Dario line, copyright,
   monogram, and shea@loopmmt.com. */

.frame {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* --- Top bar --- */
.frame > header {
  height: var(--frame-topbar);
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--paper);
  border-bottom: var(--stroke-hairline) solid var(--hairline);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--gap-wide);
}

.frame > header .wordmark {
  height: 32px;
  display: block;
  /* Fixed height, width auto; the SVG's viewBox handles ratio. */
}

.frame > header .wordmark img,
.frame > header .wordmark svg {
  height: 100%;
  width: auto;
  display: block;
}

.frame > header nav {
  display: flex;
  gap: var(--gap-wide);
}

.frame > header nav a {
  font-family: var(--font-mono);
  font-size: var(--size-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--muted);
  transition: color var(--motion-nav) var(--ease);
}

.frame > header nav a:hover,
.frame > header nav a[aria-current="page"] {
  color: var(--persimmon);
}


/* --- Main slot --- */
/* The Frame's contained block sits here. `flex: 1` lets Porch/Room/Corpus
   Frame push the footer to the natural bottom of even short pages. */

.frame > main {
  flex: 1;
  padding-top: var(--gap-wide);
  padding-bottom: var(--gap-section);
}


/* --- Footer (the Dario line lives here) --- */
.frame > footer {
  border-top: var(--stroke-hairline) solid var(--hairline);
  padding: var(--gap-wide);
  font-family: var(--font-mono);
  font-size: var(--size-label);
  line-height: var(--lh-label);
  color: var(--muted);
}

.frame > footer .footer-rows {
  max-width: var(--width-room);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--gap-tight);
}

.frame > footer .footer-mark {
  display: flex;
  align-items: center;
  gap: var(--gap);
}

.frame > footer .footer-mark svg {
  /* 60% of chrome scale — chrome is 32px, so 19px here. */
  height: 19px;
  width: auto;
}

.frame > footer .dario {
  /* WCAG note (contrast pass): routed to --muted (6.87:1 on paper)
     from the original --faint (3.31:1) to pass WCAG 2.1 AA small-text at
     the 12px Spline Mono footer size. The Dario line is a real line, not a
     decoration — it earns readable contrast. */
  color: var(--muted);
}

.frame > footer a {
  color: var(--muted);
  border-bottom: var(--stroke-hairline) solid var(--hairline);
}

.frame > footer a:hover {
  color: var(--persimmon);
  border-bottom-color: var(--persimmon);
}


/* ═══ 4. The Porch — the front page at / ═══
   Max-width 720px, centered, ~min-height 100vh. Two-line sign in the
   maker's voice, four door labels as text links (three → #coming-soon,
   one → /case), a small excerpt of recent work below (Slice 2+). */

.porch {
  max-width: var(--width-porch);
  margin: 0 auto;
  padding: var(--gap-section) var(--gap-wide);
  min-height: calc(100vh - var(--frame-topbar));
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.porch .sign {
  margin-bottom: var(--gap-section);
}

.porch .sign p {
  font-family: var(--font-display);
  font-size: var(--size-display);
  line-height: var(--lh-display);
  color: var(--ink);
  letter-spacing: var(--track-display);
  margin: 0;
}

.porch .doors {
  display: flex;
  flex-direction: column;
  gap: var(--gap-wide);
  list-style: none;
  padding: 0;
  margin: 0;
}

.porch .doors li {
  border-top: var(--stroke-hairline) solid var(--hairline);
  padding-top: var(--gap);
}

.porch .doors li:last-child {
  border-bottom: var(--stroke-hairline) solid var(--hairline);
  padding-bottom: var(--gap);
}

.porch .doors a {
  display: block;
}

.porch .doors .door-label {
  font-family: var(--font-display);
  font-size: var(--size-headline);
  line-height: var(--lh-headline);
  color: var(--ink);
  font-weight: var(--weight-display);
  transition: color var(--motion-nav) var(--ease);
}

.porch .doors a:hover .door-label {
  color: var(--persimmon);
}

.porch .doors .door-under {
  font-family: var(--font-body);
  font-size: var(--size-body);
  line-height: var(--lh-body);
  color: var(--muted);
  margin-top: var(--gap-tight);
}

/* Prose links in the porch's #still-writing note. The base `a` is
   color-inherit + no underline, so in-body porch links would read as plain
   text; give them the footer's visible treatment (muted + hairline underline
   → persimmon on hover). Scoped to `.porch section a` so the doors
   (`.porch .doors a`) and the sign are untouched. --muted on --paper is
   6.87:1 (WCAG AA small-text pass). */
.porch section a {
  color: var(--muted);
  border-bottom: var(--stroke-hairline) solid var(--hairline);
}

.porch section a:hover {
  color: var(--persimmon);
  border-bottom-color: var(--persimmon);
}


/* ═══ 5. The Room — a page-length slab about one topic ═══
   Max-width 720px, centered, min-height 100vh (freestanding).
   Structure: Headline (Fraunces display) · Lead (Spectral, one sentence) ·
   Prose passage (≤3 paragraphs) · Artifacts. */

.room {
  max-width: var(--width-room);
  margin: 0 auto;
  padding: var(--gap-section) var(--gap-wide);
  min-height: calc(100vh - var(--frame-topbar));
}

.room > header {
  margin-bottom: var(--gap-section);
}

.room > header h1 {
  margin-bottom: var(--gap);
}

.room .breath {
  font-size: var(--size-lead);
  line-height: var(--lh-lead);
  color: var(--muted);
  margin: 0 0 var(--gap-wide) 0;
  font-family: var(--font-body);
  font-weight: var(--weight-body);
}

.room .prose > p {
  margin-bottom: var(--gap);
}


/* ═══ 6. The Corpus Frame — the Score-Frame joint ═══
   J2 (the load-bearing joint of Slice 1): the site's stylesheet does
   NOT leak into the Score's body; the Score's stylesheet does NOT leak
   into the site's chrome. Mechanism:

     - Score styles live inside a top-level `.score { … }` wrapper (the
       Score's own class hooks scope naturally under this).
     - Site styles use `body > main > *:not(.score)` OR reach for classes
       (.porch, .room, .corpus-frame's wrapper) that the Score does not use.
     - The Corpus Frame is a Room whose direct child is the .score element.

   tokens.css is re-baselined to Score's live skin bit-for-bit: both
   palettes now
   share the same values (--paper #f7f2e8, --ink #221d16, --hairline #d9d0bf,
   --persimmon #bf4a20, plus --ground #efe7d7 for the notation background).
   The seam is byte-invisible.

   NOTE ON SCOPING: the site's own rules above target .frame, .porch, .room,
   .honest-badge, .corpus-frame — none of the Score's classes (.head, .clef,
   .movement, .rail, .staff, .signal, .gloss, .notation, .dyn, .coda, .sheet).
   That's the isolation — no rule in this file names a Score class, so the
   Score's own CSS (inlined at render per Score §5) governs the Score body. */

.corpus-frame {
  /* Sits inside .frame > main; carries a light hairline at its top+bottom
     to name the boundary. The Score's canonical max-width (760px, per
     score-skin-v1.css:52) is honored — the Frame's max-width does not
     constrain the Score's own centering. */
  border-top: var(--stroke-hairline) solid var(--corpus-frame-edge);
  border-bottom: var(--stroke-hairline) solid var(--corpus-frame-edge);
  background: var(--corpus-frame-bg);
  /* The Score's own .sheet element handles its own padding + max-width. */
}

/* No `.corpus-frame .score { … }` overrides — the Score's own stylesheet
   is the source of truth for its body. The Frame wraps; it does not paint. */


/* ═══ 7. The Honest Badge — top-right state chip ═══
   J4: persimmon on paper, 6px radius, 44px height, Spline Mono 12px label.
   Visible top-right on every page in pre-launch — private state; disappears
   when state is `live`. */

.honest-badge {
  position: fixed;
  top: calc(var(--frame-topbar) + var(--gap-tight));
  right: var(--gap-tight);
  z-index: 20;
  height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 0 var(--gap);
  background: var(--paper);
  color: var(--ink);
  border: var(--stroke-hairline) solid var(--persimmon);
  border-radius: var(--radius-badge);
  font-family: var(--font-mono);
  font-size: var(--size-label);
  letter-spacing: var(--track-label);
  text-transform: lowercase;
  /* WCAG note (contrast pass): label text is --ink on --paper
     (14.99:1, easy AA pass) rather than --persimmon (4.46:1, misses AA
     small-text by 0.04). Persimmon stays as the border — the color IS the
     state marker, the label stays maximally readable. Border on paper is
     4.46:1 which passes 3:1 for non-text UI (WCAG 2.1 §1.4.11).

     Real-or-Made Line: this component never counterfeits state. The
     content — "pre-launch — private" | "live" — is authored in HTML,
     never composed by CSS from a variable. When state is `live`, the
     HTML omits the element (see the sibling rule below as a defence
     in case a live surface leaves it in the markup by accident). */
}

.honest-badge[data-state="live"] {
  display: none;
}


/* ═══ 8. Responsive breakpoints (three) ═══ */

/* Comfort (≥1000px): full site — display sizes bump up (tokens.css handles
   this via its own :root override at min-width 1000px). Nothing extra here;
   the shell reads the same variables. */

/* Reading (700–999px): default set above is designed for this range. Nothing
   extra needed here either — the site's max-widths (720px Porch/Room) fit
   naturally, and the Frame's flex header wraps if the four walk labels grow
   too many. */

/* Phone (<700px): single-column, smaller padding, tighter labels. */
@media (max-width: 699px) {
  .frame > header {
    padding: 0 var(--gap);
  }
  .frame > header nav {
    gap: var(--gap);
  }
  .frame > header .wordmark {
    height: 28px;
  }

  .porch,
  .room {
    padding: var(--gap-wide) var(--gap);
  }

  .porch .doors .door-label {
    /* Section-headline size ladder is already responsive via tokens; but at
       phone we bring the door labels down one step so they don't dominate. */
    font-size: var(--size-lead);
    line-height: var(--lh-lead);
  }

  .honest-badge {
    /* On phone, the badge could crowd the top-right nav; move it just below
       the top bar with a right-edge margin. */
    top: calc(var(--frame-topbar) + var(--gap-tight));
    right: var(--gap);
  }

  .frame > footer {
    padding: var(--gap);
  }
}

/* Accessibility: reduce motion — respect the user's setting. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}

/* Focus visibility — WCAG 2.1 AA. Every interactive surface
   must show a visible focus ring for keyboard navigation. */
:focus-visible {
  outline: 2px solid var(--persimmon);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   End of shell.css. Grep test (J3):
     grep -nE '^[^/*]*#[0-9a-fA-F]{6}' shell.css
   → should return zero lines. Every colour above is var(--*).
   ═══════════════════════════════════════════════════════════════════════════ */
