/* qr.mrsealz.com — what a scanned sticker lands on.
 *
 * One screen and a short scroll. The tokens are lifted verbatim from
 * web/site/assets/css/site.css so this reads as the same object as the main
 * site — same ink, same teal, same teleprinter mono, same 800-weight display —
 * without importing a stylesheet built for a very different page.
 */
:root{
  color-scheme: dark;
  --ink:#05090a;
  --ink-2:#0a1214;
  --fog:#8fa3a4;
  --fog-dim:#5d6f70;
  --paper:#dfe8e5;
  --teal:#0ea87b;
  --teal-lit:#3fdcaa;
  --amber:#ffd9a0;
  --line:rgba(143,163,164,.18);
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, "Roboto Mono", monospace;
  --serif: Georgia, "Iowan Old Style", "Times New Roman", serif;
  --sans: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --gutter: clamp(22px, 6vw, 40px);
}

*{box-sizing:border-box}
/* the <symbol> sprite is a definitions file, not a picture — `display:none`
   would kill the <use>s in some engines, so it is collapsed instead */
.sprite{position:absolute;width:0;height:0;overflow:hidden}
body{
  margin:0;background:var(--ink);color:var(--paper);
  font-family:var(--serif);-webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
a{color:inherit}
:focus-visible{outline:2px solid var(--teal);outline-offset:3px}

main{
  position:relative;z-index:2;
  width:100%;max-width:560px;margin:0 auto;
  padding:clamp(10px,1.8vh,26px) var(--gutter) clamp(120px,22vh,180px);
}

/* ---------- shared type ---------- */
.tele{
  font-family:var(--mono);font-size:10.5px;letter-spacing:.22em;
  text-transform:uppercase;color:var(--fog-dim);margin:0;font-weight:400;
}
.tele-teal{color:var(--teal-lit)}
.tele.dim{color:var(--fog-dim);line-height:2}
/* The mark shares a row with the stamp rather than sitting on its own line —
   a band of its own would cost ~26px and push the second track card off a
   375x553 phone, which is the constraint everything here is built around. */
.masthead{display:flex;align-items:center;justify-content:space-between;gap:16px}
.mark{width:118px;height:auto;flex:none}
/* The stamp shares the masthead row with the mark and grows when a slug is
   present ("Fragment S1 · impact site"), so it is sized off the viewport rather
   than fixed — wrapping it would push the mark's row taller, and every pixel
   there comes out of the tracks' headroom. It used to carry the crash-site
   coordinates and no longer does: see qr/README.md. */
#stamp{font-size:clamp(9px,2.5vw,10.5px);letter-spacing:.14em}
.display{
  font-family:var(--sans);font-weight:800;text-transform:uppercase;
  /* The gap above the headline is viewport-relative, not a flat value, because
     it is bought out of the same budget the two track cards live on: the tall
     phones can afford real air here, the 375x553 one cannot. It is ~31px there
     and ~45px on a big phone.
     Doubling it did NOT come out of the fold — it came out of the four
     structural gaps below, each of which was carrying more than it needed on a
     short screen (see `main` padding, `.block` margin/padding, the h2 margin and
     the card gap; every one of those floors was lowered in the same change, and
     every one is a no-op on a tall phone because its vh term already wins).
     That is the pattern to repeat if this is asked for again: find the slack,
     do not spend the headroom, and never take it out of the copy — that has
     already been cut once for this same fold. */
  letter-spacing:-.035em;line-height:.9;margin:clamp(26px,5.6vh,46px) 0 11px;
  font-size:clamp(31px,9vw,58px);text-wrap:balance;
}
.narr{
  font-size:clamp(15px,3.9vw,17px);line-height:1.62;color:#c9d6d3;
  max-width:34em;margin:0 0 .6em;
}
.narr strong{color:var(--paper);font-weight:600}
.fine{
  font-family:var(--mono);font-size:10.5px;line-height:1.75;letter-spacing:.03em;
  color:var(--fog-dim);margin:18px 0 0;
}

/* ---------- the tideline ----------
   Fixed to the bottom of the viewport, behind everything. Each <g> is two
   identical wavelengths wide and slides by exactly one, so the wrap is
   invisible and there is nothing to resize or measure. Three speeds, three
   depths — the front layer carries the waterline hairline. */
.tide{
  position:fixed;left:0;right:0;bottom:0;z-index:0;pointer-events:none;
  height:min(32vh,260px);
  /* the crests fade in out of nothing and the deep water goes back to ink —
     without the second stop the bottom of every page is a solid green band */
  -webkit-mask-image:linear-gradient(to bottom,transparent 0%,#000 34%,rgba(0,0,0,.5) 100%);
          mask-image:linear-gradient(to bottom,transparent 0%,#000 34%,rgba(0,0,0,.5) 100%);
}
.tide svg{width:100%;height:100%;display:block}
/* The bodies are almost nothing; the crest lines do the drawing. Two things
   this got wrong on the way:
     - three filled layers at readable alpha stack into a flat green mass, the
       same trap as three overlapping washes in any paint program;
     - `opacity` on the <g> multiplies the stroke as well, so an 0.07 group
       turned a 0.45 crest line into 0.03 and the waves disappeared. Fill and
       stroke carry their own alpha; the group carries only the animation. */
.tide .w path{fill:var(--teal);stroke:var(--teal-lit);stroke-width:1.4;vector-effect:non-scaling-stroke}
.tide .w1{animation:drift 29s linear infinite}
.tide .w2{animation:drift 19s linear infinite reverse}
.tide .w3{animation:drift 13s linear infinite}
.tide .w1 path{fill-opacity:.055;stroke-opacity:.18}
.tide .w2 path{fill-opacity:.075;stroke-opacity:.28}
.tide .w3 path{fill-opacity:.10;stroke-opacity:.45}
@keyframes drift{from{transform:translateX(0)}to{transform:translateX(-720px)}}

.grain{
  position:fixed;inset:-50%;z-index:60;pointer-events:none;opacity:.28;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  animation:grainshift 700ms steps(2) infinite;mix-blend-mode:overlay;
}
@keyframes grainshift{0%{transform:translate(0,0)}50%{transform:translate(-2%,1%)}100%{transform:translate(1%,-1%)}}

/* ---------- the wreck ----------
   Variant D from brand/shapes/ (the entry trajectory), sitting behind the hero
   copy rather than above it. Absolute, so it costs zero vertical space — a band
   of artwork between the intro and the tracks would push the second track card
   off a 375x553 phone, and both cards staying on the first screen is a hard
   requirement here.
   Pinned to the BOTTOM of the hero so its waterline lands under the copy and its
   trajectory arcs up behind the headline, and masked on the left so the arc
   fades in rather than being cut by the viewport edge. */
.hero{position:relative}
.hero > *{position:relative;z-index:1}
.wreck{
  position:absolute;z-index:0;left:50%;transform:translateX(-50%);
  bottom:-52px;width:min(760px,150%);max-width:none;height:auto;
  opacity:.5;pointer-events:none;
  /* Two fades, intersected: horizontal so the arc enters from nothing instead of
     being cut by the viewport edge, vertical so the dense half (waterline,
     debris) sits BELOW the copy and only the faintest part of the arc passes
     behind it. Where mask-composite is unsupported the horizontal fade alone
     still applies, which is the graceful direction to fail in. */
  -webkit-mask-image:linear-gradient(to right,transparent,#000 22%,#000 88%,transparent),
                     linear-gradient(to bottom,transparent 46%,#000 82%);
          mask-image:linear-gradient(to right,transparent,#000 22%,#000 88%,transparent),
                     linear-gradient(to bottom,transparent 46%,#000 82%);
  -webkit-mask-composite:source-in;
          mask-composite:intersect;
}

/* ---------- who you found / behind the seal ---------- */
.fig{margin:0}
.fig img{width:100%;height:auto;display:block;border:1px solid var(--line);
  filter:saturate(.86) contrast(1.03)}
.fig figcaption{margin-top:8px;color:var(--fog-dim)}

/* The seal is a CUTOUT, so it gets no border and no plate: a 1px rule around a
   figure that has been cut out puts the frame straight back and undoes the
   point of it (Dave, 2026-09-05). The saturate/contrast filter goes too - it is
   there to settle PHOTOGRAPHS into the page, and this is flat line art whose one
   colour is already a house token. */
.fig-cut img{border:0;filter:none}

/* The signature. It is an inline <svg> rather than a font because this page
   loads nothing third-party; see the markup for the full reasoning.
   `fill:currentColor` means the caption's own colour carries it, so there is no
   second colour rule to keep in step. */
.sig-wrap{
  /* Given air rather than hung straight off the drawing's baseline (Dave,
     2026-09-05). The cutout has no box, so there is no frame edge to sit
     against and the signature read as if it were stuck to the seal's flipper. */
  margin-top:18px;color:var(--paper);
}
.sig{
  /* Set to the RIGHT, near the content edge, the way a signature sits at the
     end of a letter rather than centred under a picture (Dave, 2026-09-05).
     `margin-right` is 3% and not 0 on purpose: the -3deg tilt swings the top
     right corner outward, so a flush-right box would visually overhang the
     column the rest of the page is aligned to. */
  display:block;width:62%;height:auto;margin:0 3% 0 auto;fill:currentColor;
  /* Right side higher, as asked. Small on purpose: past about 4 degrees it stops
     reading as a signature written at a slight angle and starts reading as a
     page that is crooked. */
  transform:rotate(-3deg);
  transform-origin:50% 60%;
}
/* A signature is decoration with a text alternative (aria-label), so it is one
   of the few things on this page that may simply sit still for anyone who has
   asked for less motion - there is nothing to stop. The tilt is static, not an
   animation, so nothing is disabled here; noted so the next person does not go
   looking for a rule that should exist. */
#humans .fig + .fig{margin-top:18px}
.narr.small{font-size:14.5px;line-height:1.6;margin:18px 0 0;color:#b9c7c5}

/* ---------- blocks ---------- */
.block{margin-top:clamp(16px,3.4vh,48px);border-top:1px solid var(--line);padding-top:11px}
.block > h2{margin:0 0 10px}

/* ---------- tracks ----------
   A facade, not the player. Nothing is requested from SoundCloud or Spotify
   until the row is pressed — which is what lets this page ship with no consent
   banner, exactly like the main site. qr.js swaps the button for the iframe. */
.tracks{list-style:none;margin:0;padding:0}
.tracks li + li{margin-top:9px}
.trk{
  width:100%;display:grid;
  grid-template-columns:auto 1fr auto;grid-template-rows:auto auto;
  align-items:center;gap:2px 12px;
  background:rgba(10,18,20,.72);border:1px solid var(--line);
  padding:13px 14px;cursor:pointer;text-align:left;color:inherit;
  transition:border-color .25s,background .25s;
}
.trk:hover{border-color:var(--teal);background:rgba(14,168,123,.06)}
/* The cover replaces the bare "01" that used to hold this column. It is the
   only saturated colour on the page and it is the content, so it earns it —
   but it is sized to the meta block's own height (three lines ≈ 50px) plus a
   few px, so the card grows ~6px rather than being rebuilt around the artwork.
   Anything taller comes straight out of the second card's headroom below the
   fold. The fragment number moved into the source line. */
.cov{grid-column:1;grid-row:1 / span 2;position:relative;flex:none;line-height:0}
.trk .art{
  width:56px;height:56px;display:block;object-fit:cover;
  border:1px solid var(--line);filter:saturate(.9) contrast(1.02);
  transition:border-color .25s;
}
.trk:hover .art{border-color:rgba(14,168,123,.5)}
/* The fragment number rides the corner of the artwork rather than the source
   line: "01 · SOUNDCLOUD · 22.08.26" is 26 mono characters at .18em tracking
   and wraps to two lines on a 390px phone, which costs 12px per card twice —
   and both cards have to clear a 375x553 fold. Here it is a catalogue number
   stamped on the piece, which is also what it is. */
.cov .no{
  position:absolute;left:0;bottom:0;
  padding:2px 5px 2px 4px;font-size:9px;letter-spacing:.1em;line-height:1;
  background:var(--teal);color:#04120d;
}
.trk .meta{grid-column:2;grid-row:1 / span 2;display:flex;flex-direction:column;gap:2px;min-width:0}
.trk .t{
  font-family:var(--sans);font-weight:800;text-transform:uppercase;
  letter-spacing:-.02em;font-size:clamp(16px,4.4vw,19px);line-height:1.1;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* The longest credit on the page — "Jacob Pool · Mr. Sealz Remix", 28 mono
   characters — now shares the row with a 56px cover and the play ring, and at
   the old 10px/.14em it ellipsised our own name away on a 390px phone. Tracking
   came down to .10em and the size became viewport-relative, which is what
   actually clears it: measured, it fits whole at 360, 375, 390 and 430. The
   ellipsis stays as the floor below that. Re-check against THIS credit, not the
   shorter one above it, before widening either value. */
.trk .a{
  font-family:var(--mono);font-size:clamp(8.5px,2.38vw,10px);letter-spacing:.10em;
  text-transform:uppercase;color:var(--fog);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* A ringed play button rather than a loose triangle: on a phone the row IS the
   target, and the ring is what says so. It fills on hover/press instead of
   only changing colour, so the tap has somewhere to land visually. */
.trk .go{
  grid-column:3;grid-row:1 / span 2;justify-self:end;align-self:center;
  width:34px;height:34px;flex:none;border-radius:50%;
  border:1px solid rgba(14,168,123,.55);
  display:flex;align-items:center;justify-content:center;
  transition:background .25s,border-color .25s,transform .25s;
}
.trk .tri{
  width:0;height:0;margin-left:2px;
  border-style:solid;border-width:6.5px 0 6.5px 11px;
  border-color:transparent transparent transparent var(--teal-lit);
  transition:border-left-color .25s;
}
.trk:hover .go,.trk:active .go{background:var(--teal);border-color:var(--teal);transform:scale(1.06)}
.trk:hover .tri,.trk:active .tri{border-left-color:#04120d}
/* the source and the date are the quietest line on the card — the platform is
   how you will hear it, not what you came for */
.trk .src{margin-top:3px;letter-spacing:.18em}
.tracks .player{border:1px solid var(--line);background:var(--ink-2)}
.tracks .player iframe{display:block;width:100%;border:0}

/* ---------- links ---------- */
.links{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line);border:1px solid var(--line)}
@media (max-width:420px){.links{grid-template-columns:1fr}}
.links a{
  display:flex;align-items:center;gap:12px;
  background:var(--ink);padding:15px 16px;text-decoration:none;
  font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--paper);transition:background .25s,color .25s;
}
/* The glyph is `currentColor`, so the row's existing colour transition carries
   it — no second hover rule, and nothing to keep in sync. It is a fixed 16px
   box so the six labels still start on one vertical line. */
.links .ico{width:16px;height:16px;flex:none;fill:var(--fog);transition:fill .25s}
.links .ar{margin-left:auto;color:var(--fog-dim);transition:color .25s}
.links a:hover{background:var(--ink-2);color:var(--teal-lit)}
.links a:hover .ico,.links a:hover .ar{fill:var(--teal-lit);color:var(--teal-lit)}

/* ---------- footer ---------- */
#note{margin-top:clamp(40px,7vh,68px)}
/* DORMANT — the "whole record -> mrsealz.com" panel is out of index.html for
   now (see the comment there). Kept so it returns exactly as it was rather than
   being re-invented; delete both together if the idea is ever dropped. */
.whole{
  display:flex;flex-direction:column;gap:7px;text-decoration:none;
  border:1px solid var(--line);padding:18px;
  transition:border-color .25s,background .25s;
}
.whole:hover{border-color:var(--teal);background:rgba(14,168,123,.06)}
.whole .ln{
  font-family:var(--sans);font-weight:700;text-transform:uppercase;
  letter-spacing:-.015em;font-size:clamp(15px,4vw,17px);line-height:1.15;
}
.whole .ar{color:var(--teal-lit);display:inline-block;transition:transform .25s}
.whole:hover .ar{transform:translateX(5px)}
/* The sign-off. Below the fold by a long way, so it costs the first screen
   nothing — it exists to close the page on the mark rather than on the fine
   print. The rule above it is drawn short and centred so it reads as a stamp,
   not as another section. */
.signoff{display:flex;flex-direction:column;align-items:center;gap:9px;padding:6px 0 22px}
.signoff .seal{width:104px;height:auto;opacity:.62}
.signoff .tele{letter-spacing:.34em}
#note .dim{margin-top:16px}
#note .dim a{text-decoration:none;border-bottom:1px solid var(--line);padding-bottom:1px}
#note .dim a:hover{color:var(--teal-lit);border-color:var(--teal)}

/* ---------- the boot overlay ----------
   The crash, played once, and then the page. Three rules keep it from ever
   becoming a wall:
     1. It only exists when <html> carries `boot`, which an inline script in the
        head adds. No JS (or a throw there) means no overlay at all — the page
        is simply there. Fail-open is the entire point; a loader that needs JS
        to LEAVE is a black screen someone cannot dismiss while standing at a
        lamppost.
     2. The removal is a CSS animation with `forwards`, ending in
        visibility:hidden + pointer-events:none. It lifts on its own even if
        qr.js never runs; qr.js only deletes the node afterwards.
     3. Nothing waits on the network. The page loads underneath at its own
        speed and the overlay is gone at a fixed 1.24s either way — waiting for
        `load` here would be a five-second black screen on mobile data, which is
        exactly the connection this page is designed for.
   The 2.45s total is Dave's call (2026-08-30: *"the transition time needs to be
   longer, you can't even understand the effect"*) — the first pass ran 1.24s and
   the crash was over before it read as a crash. It is the one number here in
   tension with the page's own brief, so change it deliberately: the lift's delay
   below is the only value that sets it.
   Reduced motion never gets here: the head script opts out before adding the
   class. */
#boot{display:none}
.boot #boot{
  display:flex;align-items:center;justify-content:center;
  position:fixed;inset:0;z-index:200;overflow:hidden;background:var(--ink);
  animation:boot-out .5s cubic-bezier(.4,0,.2,1) 1.95s forwards;
}
/* wider than the viewport on purpose, so the arc enters from off-screen rather
   than from a visible starting point. The overflow is clipped by #boot above —
   a fixed element's overflow can otherwise reach the document scroll width.
   `flex:none` is load-bearing: #boot is a flex container, and a flex item's
   default shrink factor was quietly overriding that width on exactly the
   screens it was written for — at 390px the svg came out 390 wide instead of
   585, so the arc began at the visible left edge rather than off it. */
.boot #boot svg{width:min(150%,760px);height:auto;flex:none}
@keyframes boot-out{
  from{opacity:1}
  99%{opacity:0;visibility:visible}
  to{opacity:0;visibility:hidden;pointer-events:none}
}

/* The entry arc draws itself. pathLength=1 on the element, so the dash is
   literally 1 -> 0 and the path can be re-shaped without touching this.
   Three strokes on ONE path — ~2.2px solid with a 3.5px and a 7px pass behind
   it — which is how the heat is drawn without an feGaussianBlur (a filter on a
   full-screen animated element is the wrong thing to hand a cheap phone). They
   share the `d` and the animation, so the glow cannot drift away from the line
   the way the old parallel dotted path did.
   ⚠ THESE THREE MUST NOT CARRY `vector-effect:non-scaling-stroke`, and that is
   the whole bug Dave saw twice (2026-08-30 "the tail is split in multiple
   parts", again on 08-31 after it was supposedly fixed). `pathLength="1"`
   normalises the dash values against the path's length in USER space, while
   non-scaling-stroke makes the browser lay the dashes out in DEVICE space — so
   the dash unit ends up wrong by exactly the SVG's scale factor (760/400 =
   1.9 on any viewport ≥507px). Two visible consequences, both of which were
   misread as drawing mistakes and "fixed" by moving coordinates:
     • the drawn head lags at progress/1.9, so the arc reaches only 53% of its
       own path at the end of the draw and stops in mid-air;
     • the pattern REPEATS, so the second dash slides in from the end and sits
       there detached — the "split tail", a streak near the impact with nothing
       joining it to the arc. Reproduced at t=330ms: head at 38%, second dash
       from 91% to 100%.
   Widths are therefore in user units (2.2 : 3.5 : 7 becomes 1.35 : 2.15 : 4.3)
   and now scale WITH the drawing: ~2.0px on a phone, ~2.6px on a desktop. That
   drift is deliberate — a breakpoint that pinned the weight would put a visible
   step in the line's thickness at one window width, which is worse than a
   full-screen graphic being a shade bolder on a big screen.
   The easing decides whether the first fifth of a second is black. A slow-in
   curve (.32,0,…) drew almost nothing for the first 250ms, which on a loader
   this length is a quarter of it spent looking broken. This one starts fast and
   settles into the impact, which is also the right shape for something coming
   down. */
.b-traj,.b-glow{
  fill:none;stroke:#3fdcaa;stroke-linecap:round;
  stroke-dasharray:1;stroke-dashoffset:1;
  animation:draw 1.05s cubic-bezier(.2,.65,.35,1) forwards;
}
.b-traj{stroke:url(#bTraj);stroke-width:1.35}
.b-glow1{stroke-width:4.3;opacity:.09}
.b-glow2{stroke-width:2.15;opacity:.2}
@keyframes draw{to{stroke-dashoffset:0}}

/* it goes under — and not before it arrives. The flare used to fire at .85s
   while the arc drew until 1.05s, so the impact happened above an object still
   on its way down. Everything below is keyed off the arc LANDING. */
.b-hot{transform-origin:258px 153px;opacity:0;animation:hot .45s ease-out 1s forwards}
@keyframes hot{
  0%{opacity:0;transform:scale(.35)}
  55%{opacity:1;transform:scale(1.06)}
  100%{opacity:.72;transform:scale(1)}
}

/* the water closes over it — drawn out from the point of entry, which is why it
   is scaled on X rather than dashed */
.b-water{
  fill:none;stroke:#3fdcaa;stroke-width:1.3;vector-effect:non-scaling-stroke;
  opacity:0;transform:scaleX(.2);transform-origin:258px 153px;
  animation:water .55s cubic-bezier(.2,.7,.3,1) 1.05s forwards;
}
@keyframes water{to{opacity:.72;transform:scaleX(1)}}

/* and is thrown forward of it. These replace two straight lines that met at the
   impact point and read, at this size, as a pair of crossed sticks. */
.b-splash path{
  fill:none;stroke:#3fdcaa;stroke-width:1.1;stroke-linecap:round;
  vector-effect:non-scaling-stroke;
  opacity:0;transform:translateX(-6px);transform-origin:258px 153px;
  animation:splash .4s cubic-bezier(.15,.7,.35,1) 1.1s forwards;
}
.b-splash path:nth-child(2){animation-delay:1.18s}
@keyframes splash{to{opacity:.5;transform:translateX(0)}}

/* and this is all anyone ever finds */
.b-deb rect{fill:#8fa3a4;opacity:0;animation:fade-in .28s ease-out forwards}
.b-deb rect:nth-child(1){animation-delay:1.34s}
.b-deb rect:nth-child(2){animation-delay:1.40s}
.b-deb rect:nth-child(3){animation-delay:1.46s}
.b-deb rect:nth-child(4){animation-delay:1.38s}
.b-deb rect:nth-child(5){animation-delay:1.50s}
.b-deb rect:nth-child(6){animation-delay:1.56s}
.b-deb rect:nth-child(7){animation-delay:1.52s}
@keyframes fade-in{to{opacity:.78}}

/* There is still deliberately no `prefers-reduced-motion` block for the tide,
   the grain or the hover transitions — the reasoning is in web/README.md
   § Motion and it applies to the same audience. If that is ever reversed, the
   tide drift is the one thing to gate.
   The boot overlay IS gated, and it is not a reversal of that decision: a
   full-screen animation that owns the viewport for a second is a different
   proposition from a background that drifts. It opts out in the head script,
   before the class is ever added, so the reduced-motion path runs no overlay
   code at all rather than a shortened version of it. */
