/* --------------------------------------------------------------------
   Exonero — public site.

   Committed to one look rather than following the viewer's theme: the
   page is a dusk desert seen from orbit, and a light variant of that is
   not the same page. Every colour is stated on :root so nothing here
   depends on a media query resolving.
   -------------------------------------------------------------------- */
:root {
    --ink:    #0a0806;   /* the ground at night */
    --dust:   #cdbfa8;   /* body text: bone, not white */
    --bright: #f2e9dc;
    --amber:  #d8963c;   /* the signal colour, used sparingly */
    --rust:   #8a4a2c;
    --rule:   rgba(205, 191, 168, 0.16);
    --panel:  rgba(12, 10, 8, 0.62);

    --sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
    --serif: Georgia, "Iowan Old Style", "Times New Roman", serif;
    --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    /* The memo face. The fallbacks are the narrowest grotesques likely to
       be installed rather than a generic sans: swapping to something wide
       would reflow the whole dispatch. */
    --memo: "Barlow Condensed", "Roboto Condensed", "Arial Narrow", sans-serif;
}

/* Self-hosted rather than linked from Google, so the page makes no
   third-party request. Latin subset only, 14KB a weight. SIL Open Font
   License. Two weights: 400 for the order itself, 600 for the header and
   sign-off, which are spaced-out caps and go thin without it. */
@font-face {
    font-family: "Barlow Condensed";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("assets/fonts/barlow-condensed-400-latin.woff2") format("woff2");
}
@font-face {
    font-family: "Barlow Condensed";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("assets/fonts/barlow-condensed-600-latin.woff2") format("woff2");
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
    margin: 0;
    background: var(--ink);
    color: var(--dust);
    font-family: var(--serif);
    font-size: 17px;
    line-height: 1.72;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

/* The sky. A dusk gradient with the horizon a little below centre, and a
   low glow where the sun has already gone. Fixed, so the whole page reads
   as one continuous view rather than a stack of cards. */
.sky {
    position: fixed;
    inset: 0;
    z-index: -2;
    background:
        radial-gradient(120% 55% at 50% 68%, rgba(216, 150, 60, 0.20) 0%, rgba(138, 74, 44, 0.10) 34%, rgba(10, 8, 6, 0) 70%),
        radial-gradient(80% 40% at 78% 12%, rgba(90, 110, 150, 0.10) 0%, rgba(10, 8, 6, 0) 60%),
        linear-gradient(180deg, #05060a 0%, #0b0a0c 38%, #17110d 62%, #0a0806 100%);
}

/* Film grain, so the flat gradients above do not band on a big screen.
   Inline SVG turbulence: no request, no dependency, and it costs one
   composite layer. */
.grain {
    position: fixed;
    inset: -50%;
    z-index: -1;
    opacity: 0.30;
    pointer-events: none;
    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='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* ---- screen streaks -------------------------------------------------- */

/* The dispatch's scanlines, escaped onto the page. Every so often a soft band
   climbs the viewport, the way a roll bar crawls up a CRT that has not quite
   locked. Fixed and pointer-events: none, so it can never touch layout or
   swallow a click, and it animates transform and opacity only, which keeps the
   whole pass on the compositor and off the main thread. Nodes are built and
   destroyed per pass rather than parked, and app.js caps them at two at once. */
.streaks {
    position: fixed;
    inset: 0;
    z-index: 3;
    overflow: hidden;
    pointer-events: none;
}

.streak {
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 180px;
    will-change: transform, opacity;
    background: linear-gradient(180deg,
        rgba(255, 138, 116, 0) 0%,
        rgba(255, 138, 116, 0.05) 42%,
        rgba(255, 176, 156, 0.15) 50%,
        rgba(255, 138, 116, 0.05) 58%,
        rgba(255, 138, 116, 0) 100%);
    animation: streak-up var(--dur, 2200ms) linear forwards;
}

/* Occasionally the packet's blue rather than the dispatch's red, so both
   documents get a say in what the page is doing. */
.streak.cool {
    background: linear-gradient(180deg,
        rgba(125, 180, 236, 0) 0%,
        rgba(125, 180, 236, 0.045) 42%,
        rgba(172, 208, 244, 0.13) 50%,
        rgba(125, 180, 236, 0.045) 58%,
        rgba(125, 180, 236, 0) 100%);
}

@keyframes streak-up {
    from { transform: translate3d(0, 0, 0); opacity: 0; }
    14%  { opacity: 1; }
    86%  { opacity: 1; }
    to   { transform: translate3d(0, calc(-100vh - 180px), 0); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) { .streaks { display: none; } }

/* ---- hero --------------------------------------------------------- */

.hero {
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 8vh 24px 12vh;
    position: relative;
}

.hero-inner { max-width: 720px; }

.hero-kicker {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.42em;
    text-transform: uppercase;
    color: rgba(205, 191, 168, 0.45);
    margin: 0 0 34px;
}

/* Typographic wordmark. Wide-tracked, light, and letterspaced far enough
   that it reads as a mark rather than as a word in a sentence. */
.wordmark {
    font-family: var(--sans);
    font-weight: 200;
    font-size: clamp(46px, 12vw, 116px);
    letter-spacing: 0.30em;
    text-indent: 0.30em;   /* recover the trailing track so it stays centred */
    text-transform: uppercase;
    line-height: 1;
    margin: 0;
    color: var(--bright);
    text-shadow: 0 0 46px rgba(216, 150, 60, 0.30);
}

.lede {
    font-family: var(--sans);
    font-weight: 300;
    font-size: clamp(19px, 3vw, 27px);
    line-height: 1.35;
    color: var(--bright);
    margin: 30px 0 0;
}

/* An open channel: a hairline with one bright pip travelling along it.
   The only moving thing above the fold, and it stops under reduced-motion. */
.carrier {
    width: min(360px, 70vw);
    height: 1px;
    margin: 30px auto 0;
    background: var(--rule);
    position: relative;
    overflow: hidden;
}
.carrier span {
    position: absolute;
    top: -1px;
    left: -30%;
    width: 30%;
    height: 3px;
    background: linear-gradient(90deg, rgba(216,150,60,0) 0%, var(--amber) 50%, rgba(216,150,60,0) 100%);
    animation: sweep 5.5s linear infinite;
}
@keyframes sweep { to { left: 100%; } }
@media (prefers-reduced-motion: reduce) {
    .carrier span { animation: none; left: 35%; opacity: 0.5; }
}

/* Two phrases in here rewrite themselves, which changes the line count as they
   go. JS measures the longest combination once the webfont has loaded and pins
   min-height to it, so the block below never jumps mid-sentence. */
.sub {
    max-width: 50ch;
    margin: 28px auto 0;
    color: rgba(205, 191, 168, 0.78);
    font-size: 16px;
}

.swap { color: rgba(216, 150, 60, 0.92); }

/* The caret only exists while that slot is actually typing, so the line is not
   permanently a few pixels wider than it reads. */
.swap.typing::after {
    content: "";
    display: inline-block;
    width: 1px;
    height: 0.95em;
    margin-left: 2px;
    vertical-align: -0.12em;
    background: rgba(216, 150, 60, 0.92);
    animation: caret 1s steps(1, end) infinite;
}
@keyframes caret { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .swap.typing::after { animation: none; } }

.status {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: rgba(205, 191, 168, 0.5);
    margin: 42px 0 0;
}
.pip {
    display: inline-block;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--amber);
    margin-right: 9px;
    vertical-align: 1px;
}

.scroll-cue {
    position: absolute;
    bottom: 34px;
    left: 50%;
    transform: translateX(-50%);
    width: 1px;
    height: 44px;
    background: var(--rule);
    overflow: hidden;
}
.scroll-cue span {
    position: absolute;
    inset: 0 auto auto 0;
    width: 1px; height: 14px;
    background: rgba(205, 191, 168, 0.65);
    animation: drop 2.6s ease-in-out infinite;
}
@keyframes drop { 0% { top: -14px; } 60%, 100% { top: 44px; } }
@media (prefers-reduced-motion: reduce) { .scroll-cue span { animation: none; top: 15px; } }

/* ---- panels ------------------------------------------------------- */

main { padding: 0 24px; }

.panel {
    max-width: 640px;
    margin: 0 auto;
    padding: 13vh 0;
    border-top: 1px solid var(--rule);
}
.panel-wide { max-width: 760px; }
.panel-close { padding-bottom: 9vh; }

.eyebrow {
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.34em;
    text-transform: uppercase;
    color: var(--amber);
    opacity: 0.75;
    margin: 0 0 22px;
}

.panel h2 {
    font-family: var(--sans);
    font-weight: 200;
    font-size: clamp(27px, 4.6vw, 42px);
    line-height: 1.18;
    letter-spacing: -0.01em;
    color: var(--bright);
    margin: 0 0 30px;
    max-width: 20ch;
}
.panel-wide h2 { max-width: 24ch; }

.body { margin: 0 0 22px; max-width: 62ch; }
.body:last-child { margin-bottom: 0; }

.pull {
    margin: 40px 0 0;
    padding: 0 0 0 22px;
    border-left: 1px solid var(--amber);
    font-family: var(--sans);
    font-weight: 300;
    font-size: clamp(19px, 2.6vw, 24px);
    line-height: 1.45;
    color: var(--bright);
    max-width: 34ch;
}

/* ---- the two documents ---------------------------------------------- */

/* Both are the same kind of object, a sheet that reached you, so they share a
   frame and a face and differ only in how they were delivered. The dispatch is
   projected: red, scanlined, lit from inside. The relay packet came off a wire
   and was printed: blue, ruled, flat. They tilt in opposite directions by well
   under a degree, which is enough to read as two loose sheets instead of one
   column of boxes, and small enough that no line of text looks crooked. */
.dispatch,
.relay {
    position: relative;
    margin: 34px 0 0;
    padding: 26px 26px 28px;
    font-family: var(--memo);
    font-size: 1.16rem;
    line-height: 1.62;
    letter-spacing: 0.015em;
}

.d-head,
.r-head {
    margin: 0;
    padding-bottom: 14px;
    font-weight: 600;
    font-size: 0.9rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    line-height: 1.72;
}

.d-end,
.r-end {
    margin: 22px 0 0;
    padding-top: 14px;
    font-weight: 600;
    font-size: 0.9rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
}

/* ---- the dispatch: a red projection ---------------------------------- */

.dispatch {
    transform: rotate(-0.7deg);
    border: 1px solid rgba(255, 106, 82, 0.34);
    background:
        linear-gradient(180deg, rgba(255, 106, 82, 0.085), rgba(255, 106, 82, 0.02)),
        rgba(20, 6, 4, 0.66);
    color: rgba(255, 158, 138, 0.94);
    text-shadow: 0 0 7px rgba(255, 106, 82, 0.42);
    box-shadow: 0 0 30px rgba(255, 106, 82, 0.10),
                inset 0 0 44px rgba(255, 106, 82, 0.05);
}

/* Scanlines belong to the projector, not to the page, so they lie over the
   text rather than tinting it. An absolutely positioned pseudo-element paints
   above in-flow content by default, which is what puts them on top; it must
   never swallow a click or a text selection, hence pointer-events. */
.dispatch::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: repeating-linear-gradient(
        180deg,
        rgba(255, 106, 82, 0.075) 0 1px,
        transparent 1px 4px);
}

/* A beam is brightest where it lands, so the leading edge runs hotter than
   the frame around it and fades out before the corners. */
.dispatch::after {
    content: "";
    position: absolute;
    top: -1px;
    left: -1px;
    right: -1px;
    height: 1px;
    pointer-events: none;
    background: linear-gradient(90deg, transparent,
        rgba(255, 146, 124, 0.95) 20%, rgba(255, 146, 124, 0.95) 80%, transparent);
}

.d-head {
    color: rgba(255, 180, 160, 0.96);
    border-bottom: 1px solid rgba(255, 106, 82, 0.3);
}
.d-end {
    color: rgba(255, 138, 116, 0.52);
    border-top: 1px solid rgba(255, 106, 82, 0.3);
}

.d-meta {
    margin: 16px 0 0;
    padding: 0 0 16px;
    border-bottom: 1px solid rgba(255, 106, 82, 0.3);
    display: grid;
    grid-template-columns: 5.5rem 1fr;
    gap: 2px 10px;
    font-size: 1.05rem;
    letter-spacing: 0.05em;
}
.d-meta dt { color: rgba(255, 138, 116, 0.58); text-transform: uppercase; letter-spacing: 0.14em; }
.d-meta dd { margin: 0; color: rgba(255, 206, 192, 0.98); }

.d-body {
    margin: 20px 0 0;
    padding: 0 0 0 1.9rem;
}
.d-body li { margin: 0 0 15px; }
.d-body li:last-child { margin-bottom: 0; }
.d-body li::marker { color: rgba(255, 138, 116, 0.58); }

/* ---- the relay packet: a blue wire bulletin -------------------------- */

.relay {
    transform: rotate(0.55deg);
    margin-top: 26px;
    border: 1px solid rgba(125, 180, 236, 0.26);
    background:
        linear-gradient(180deg, rgba(125, 180, 236, 0.05), rgba(125, 180, 236, 0.012)),
        rgba(6, 12, 22, 0.72);
    color: rgba(206, 224, 244, 0.92);
    box-shadow: 0 0 26px rgba(125, 180, 236, 0.07);
}

/* A double rule under the masthead and a hairline above every item: the two
   marks that make a block of text read as a bulletin rather than a memo. */
.r-head {
    color: rgba(172, 208, 244, 0.96);
    border-bottom: 3px double rgba(125, 180, 236, 0.42);
}
.r-end {
    color: rgba(125, 180, 236, 0.5);
    border-top: 1px solid rgba(125, 180, 236, 0.26);
}

.r-list { margin: 22px 0 0; }
.r-list dt {
    margin: 0 0 5px;
    padding-top: 14px;
    border-top: 1px solid rgba(125, 180, 236, 0.18);
    color: rgba(125, 180, 236, 0.66);
    font-weight: 600;
    font-size: 0.9rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
}
.r-list dt:first-child { padding-top: 0; border-top: 0; }
.r-list dd { margin: 0 0 18px; }
.r-list dd:last-child { margin-bottom: 0; }

/* ---- redaction bars -------------------------------------------------- */

/* A bar is ink laid over the line it interrupts, so it takes that line's own
   colour. Both sheets are now monochrome, so every bar inherits rather than
   carrying the old bone colour, which would read as a third document. */
.dispatch .rd,
.relay .rd { background: currentColor; opacity: 0.85; }

/* A bar is an inline-block, so a line can break between it and whatever
   punctuation follows, stranding a comma at the start of the next line.
   Anything glued to a bar with no space rides with it. */
.rd-run { white-space: nowrap; }
/* Punctuation glued to a bar should sit against it, not float off the end
   on the bar's own right margin. */
.rd-run .rd { margin-right: 0; }

.rd {
    display: inline-block;
    width: calc(var(--w, 8) * 1ch);
    height: 0.82em;
    margin: 0 0.14em;
    vertical-align: -0.06em;
    background: rgba(205, 191, 168, 0.82);
    border-radius: 1px;
}

/* The discovery run sits under the dispatch, so it needs its own air above it;
   .after is the lead-in and loses its own top margin inside the group. */
.discovery { margin-top: 46px; }
.discovery .f-list {
    margin: 0;
    padding: 0;
    list-style: none;
    max-width: 60ch;
}
.f-list li {
    position: relative;
    margin: 0 0 9px;
    padding-left: 20px;
    line-height: 1.5;
}
.f-list li:last-child { margin-bottom: 0; }
.f-list li::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 0.62em;
    width: 7px;
    height: 1px;
    background: var(--amber);
    opacity: 0.8;
}

.after { margin: 0 0 34px; }

/* Each expectation is a small heading over its own run of body copy, so the
   section reads as four things a player can expect rather than one block of
   prose. The heading reuses the eyebrow's proportions: it is the same rank of
   label, just repeated down the page. .body zeroes its own last-child margin,
   so the gap between facets comes from .facet alone and stays even. */
.facet { margin: 30px 0 0; }
.facet:first-of-type { margin-top: 0; }
.f-head {
    font-family: var(--mono);
    font-weight: 400;
    font-size: 10px;
    letter-spacing: 0.34em;
    text-transform: uppercase;
    color: var(--amber);
    opacity: 0.75;
    margin: 0 0 15px;
}

.after {
    margin: 30px 0 0;
    font-family: var(--serif);
    font-size: 1.06rem;
    font-style: italic;
    color: rgba(205, 191, 168, 0.66);
}

/* ---- footer ------------------------------------------------------- */

footer {
    max-width: 640px;
    margin: 0 auto;
    padding: 8vh 24px 12vh;
    border-top: 1px solid var(--rule);
    text-align: center;
}
.foot-title {
    font-family: var(--sans);
    font-weight: 200;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    font-size: 15px;
    color: var(--bright);
    margin: 0 0 14px;
}
.foot-line {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: 0.06em;
    color: rgba(205, 191, 168, 0.45);
    margin: 0 0 8px;
}
footer a { color: rgba(216, 150, 60, 0.85); text-decoration: none; border-bottom: 1px solid var(--rule); }
footer a:hover { color: var(--amber); }

/* ---- preview-only live badge -------------------------------------- */

.livebadge {
    position: fixed;
    left: 14px;
    bottom: 14px;
    z-index: 50;
    display: none;
    align-items: center;
    gap: 8px;
    padding: 7px 12px;
    background: rgba(10, 8, 6, 0.86);
    border: 1px solid var(--rule);
    border-radius: 999px;
    font-family: var(--mono);
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgba(205, 191, 168, 0.62);
}
.livebadge.on { display: flex; }
.livebadge .dot {
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--amber);
    animation: breathe 2.4s ease-in-out infinite;
}
.livebadge.updating { color: var(--bright); border-color: rgba(216, 150, 60, 0.5); }
@keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.28; } }
@media (prefers-reduced-motion: reduce) { .livebadge .dot { animation: none; } }

@media (max-width: 560px) {
    body { font-size: 16px; }
    .panel { padding: 10vh 0; }
    .wordmark { letter-spacing: 0.22em; text-indent: 0.22em; }
}
