/* memechimp — the one stylesheet for all four screens.
   THEME: COMPOSITION BOOK. The page is ruled paper; everything on it is drawn in pen or pencil.

   The palette is taken from the object itself, not invented:
     - the page          warm off-white, the colour of cheap bound paper
     - the printed rules pale blue horizontals, one red vertical margin
     - the pen           ink blue — all text, all outlines, every primary action
     - the pencil        graphite — labels, hints, and anything not yet committed in ink
     - the red pen       corrections, and the one destructive-ish action (re-submit)

   THREE DEVIATIONS FROM /pastel, all owner-mandated:
     1. border-radius: 6px. /pastel §2.1 bans radius outright; the owner asked for slightly-round
        edges. Capped at 6px. (.ring is the exception — a circle is a circle.)
     2. More than one hue. /pastel §5 wants a single hue family; a composition book is BY DEFINITION
        blue rules plus a red margin plus grey pencil, so the theme is three families by design.
        This is also what finally makes the placeholder text legitimately grey: it is pencil.
     3. Gradients. /pastel §5 bans them — but decorative ones (it uses a repeating-conic
        checkerboard itself). The two below are HARD-STOP line patterns that draw the ruled paper;
        there is not one soft colour transition in this file, and no other element in the app carries
        a gradient at all. The sweep asserts exactly that.

   Everything else in /pastel is binding: no blur, no neon, no hairlines, no eased hover transitions,
   no icon libraries. Shadows are tinted and blur-free.

   LAW-1 — FILL = CLICKABLE. The ONLY elements with a solid background are <button> and
   <a class="btn">. Everything else is outline-only, drawn straight onto the ruled page. That is what
   makes "no cards" a property a harness can measure rather than a claim. If you are about to add
   `background:` to a rule below, the element had better be a button. */

:root{
  --paper:#FBFAF4;         /* the page — warm off-white, never pure white */
  --rule:#B9CFE6;          /* the printed horizontal rules */
  --margin:#E3969C;        /* the printed red margin line */

  --ink:#1F3A66;           /* PEN — all text, all outlines */
  --accent:#2F5FA8;        /* pen blue — primary buttons, selection */
  --accent-dark:#1B4079;   /* pressed pen */
  --accent-soft:#A6C0DF;   /* THE SHADOW COLOUR */
  --accent-faint:#DCE7F5;  /* default button fill, chips */

  --pencil:#767B82;        /* PENCIL — labels, secondary text, anything not inked */
  --pencil-soft:#B4B8BD;   /* light graphite — hints, empty openings, placeholders */

  --good:#3F7D5C;          /* green pen — upload done */
  --warn:#C39433;          /* yellow pencil — upload in flight, pending */
  --danger:#C0392E;        /* RED PEN — re-submit, reject */
  --danger-faint:#E6ADA8;  /* light red — empty / required */
  --r:6px;
  --pitch:28px;            /* the printed rule pitch — every vertical metric is a multiple of it */
  --gap:28px;
}

*{box-sizing:border-box;background:transparent}   /* LAW-1, stated once, at the top */
html,body{margin:0;padding:0}

/* ---------- the ruled page ----------
   Two hard-stop layers and nothing else: one red vertical margin, then blue horizontals repeating
   forever. Both scroll with the page, because it is paper, not a backdrop.

   The margin line is POSITIONED against the content column, not against the viewport. Pinned to a
   fixed inset it drifts out into empty space on a wide screen and reads as a stray red line; a
   composition book has the writing starting just to the right of the margin, which is what the
   max() does — it tracks the wrap's left edge (max-width 760 + 22px body padding) and sits 18px
   clear of it, collapsing to the page edge once the content stops being centred. */
body{
  min-height:100vh;
  background-color:var(--paper);
  background-image:
    linear-gradient(var(--margin), var(--margin)),
    repeating-linear-gradient(to bottom, transparent 0, transparent 27px, var(--rule) 27px, var(--rule) 28px);
  /* the margin layer is sized to the LINE, not to the page: a percentage background-position
     resolves against (positioning area - image size), so a full-width layer has nowhere to move
     and the max() below would collapse to its floor and pin the line to the page edge. */
  background-size:2px 100%, auto;
  background-position:max(10px, calc(50% - 420px)) 0, 0 0;
  background-repeat:no-repeat, repeat;
  color:var(--ink);
  /* THE GRID (AUDIT-P2 §A — measured, not guessed).
     Rules sit at y = 27 + 28k. A 13px/28px Consolas line box puts its baseline 18px down, so
     blockTop + 18 = 27 (mod 28)  =>  blockTop = 9 (mod 28). Hence the 9px top padding: it drops
     the first line so its baseline lands exactly ON the first printed rule. Every vertical metric
     below is a whole multiple of --pitch, so nothing downstream falls off the ruling. */
  font:13px/28px Consolas,"Courier New",monospace;
  padding:9px 22px 84px;
}
img{max-width:100%;display:block;image-rendering:auto}
a{color:inherit;text-decoration:none}
::selection{background:var(--accent-soft);color:var(--ink)}

/* THE GRID POLICY, in three lines:
     - a block containing WRITING has (border-top + padding-top) a whole pitch, and a whole-pitch
       height, so its lines and everything after it stay on the ruling
     - a control whose label is one word or one glyph (button, chip, badge) is a MARK: whole-pitch
       height, label centred inside it — the box is on the grid, the label is in the middle of it
     - a PHOTOGRAPH keeps its own height; the space it occupies is snapped instead (see app.js)

   THE BASELINE RULE, for anything larger than body type.
   Baseline offset inside a line box = 0.3019*F + L/2 (fitted to two measured points, AUDIT-P2 §A).
   A block starting at 9 (mod 28) needs padding-top = (18 - offset) mod 28 to land its baseline on a
   printed rule, plus a padding-bottom that rounds the box to a whole number of pitches. Only ~13px
   text lands for free — every heading below is pushed onto the line on purpose. */

/* ---------- 2. wrap ---------- */
.wrap{max-width:760px;margin:0 auto}
/* a single-column screen (the submission) reads badly at wall width — this is a MODIFIER on the
   existing component, not a thirteenth component. */
.narrow .wrap{max-width:680px}
body.narrow:has(.queue) .wrap{max-width:780px}

/* ---------- 3 + 4. sect / entry — THE INDEX ----------
   A LIST, not a grid. Each item is two ruled lines tall: the thumbnail stands in both of them at the
   left, the title is written on the lower rule beside it, the thumbs-up sits at the end of the line.

   ONE BLANK RULE BETWEEN GROUPS, like a new paragraph. It comes from the heading's own top padding
   (which is there anyway, to drop a larger heading onto a rule) — NOT from a margin on the section.
   That is what makes it self-maintaining: every item is a whole number of pitches, so adding one to
   any category pushes everything below it down by exactly two ruled lines and the paragraph break
   between the next two groups stays exactly one line, with nothing to recalculate. */
.sect{display:block;margin:0}
.sect h2{
  margin:0;padding:27px 0 1px;
  font-size:18px;font-weight:700;line-height:var(--pitch);
  letter-spacing:2.4px;text-transform:uppercase;color:var(--ink);
}

.entry{
  position:relative;
  display:flex;align-items:center;gap:0;
  height:var(--pitch);                       /* ONE ruled line per item */
  white-space:nowrap;
}
/* the bullet — this is a list, so it is marked like one */
.entry[data-id]::before{
  content:"\2022";
  flex:0 0 auto;width:20px;
  color:var(--accent-soft);font-size:15px;line-height:var(--pitch);
}
/* the title, HANDWRITTEN. Ink Free at 17px puts its baseline 18px into the line box — the same
   place Consolas 13px does — so it needs no compensation to sit on the rule. */
.entry > a{
  font-family:"Ink Free","Segoe Print","Comic Sans MS",cursive;
  font-size:17px;line-height:var(--pitch);
  overflow:hidden;text-overflow:ellipsis;
}
.entry > a:hover{color:var(--accent)}
/* by NAME — all blue, no grey anywhere on the line */
.entry em{flex:0 0 auto;font-style:normal;margin-left:10px;
  font-size:12px;line-height:var(--pitch);letter-spacing:1.2px;text-transform:uppercase;
  color:var(--accent-soft)}
.entry em b{font-weight:400;color:var(--accent)}
/* the one way in, at the foot of the list */
.entry.open{display:block;height:var(--pitch);line-height:var(--pitch);padding:0;
  color:var(--accent-soft);font-size:22px}
.entry.open:hover{color:var(--accent)}

/* the star, ATTACHED to the name — not parked in a right-hand column, because a list has no columns */
.thumbs{
  flex:0 0 auto;margin-left:8px;
  padding:0;border:0;background:transparent;box-shadow:none;
  width:var(--pitch);height:var(--pitch);line-height:0;
  display:flex;align-items:center;justify-content:center;
  color:var(--accent-soft);
}
.thumbs:hover{background:transparent;color:var(--good)}
.thumbs:active{transform:none;box-shadow:none}
.thumb{width:24px;height:24px;display:block}
.thumb + .thumb{display:none}                       /* the filled one waits */
.entry.liked .thumbs{color:var(--good)}
.entry.liked .thumb{display:none}
.entry.liked .thumb + .thumb{display:block;width:27px;height:27px}   /* filled, and larger */
/* the hover preview — the FULL set of images, large, opening into the empty half of the page.
   It expands to the RIGHT of the list rather than below it: the list column is 760px and there is
   several hundred pixels of blank paper beside it, which is exactly where a big picture belongs.

   The width is clamped against the viewport (100% here resolves to the entry's own width), so the
   panel takes what space there is and can never push the page sideways. Below 1150px there is no
   empty half to open into, so it does not open. */
.peek{
  position:absolute;left:calc(100% + 24px);top:-14px;z-index:6;
  display:none;flex-direction:column;gap:var(--pitch);
  /* The panel opens at  wrapLeft + 760 + 24 , and wrapLeft is (100vw - 804)/2 + 22 for a centred
     760px column, so the room left before the right margin is  50vw - 426px . Clamping on the
     column width alone (as this first did) ignores the offset and overflows by ~80px. */
  width:min(520px, calc(50vw - 430px));
  padding:25px;
  border:3px solid var(--ink);border-radius:var(--r);
  background:var(--paper);box-shadow:5px 5px 0 var(--accent-soft);
}
.entry:hover .peek{display:flex}
.peek img{width:100%;height:196px;object-fit:cover;   /* 7 pitches */
  border:2px solid var(--ink);border-radius:var(--r)}
@media(max-width:1300px){.peek{display:none !important}}   /* below this there is no empty half to open into */

/* ---------- 15. doodle — the owner's own words, at the foot of the book ----------
   The belief first, then the quote under it, filling the whole column.

   The quote is HANDWRITTEN: Segoe Script is a real Windows face, so this costs no webfont and no
   network. At 36px it measures 744px against a 760px column — it fills the page — and its baseline
   sits 52px into an 84px line box, so 22px of lift lands it on a printed rule and 6px below rounds
   the block to four whole pitches. Every one of those numbers was measured, not guessed. */
.doodle{display:block;margin:calc(var(--pitch) * 2) 0 0}
/* 17px Consolas lands 2px below the rule where 17px Ink Free lands exactly on it — different
   faces, different metrics. A relative nudge fixes it and costs no layout. */
.doodle p{margin:0;font-size:17px;line-height:var(--pitch);color:var(--ink);
  padding:0 0 var(--pitch);position:relative;top:-2px}
.doodle p.q{top:0}
.doodle p.q{
  font-family:"Segoe Script","Segoe Print","Bradley Hand","Brush Script MT",cursive;
  font-size:36px;line-height:84px;padding:22px 0 6px;   /* 4 pitches */
}

/* The quote is a link, but it does not announce itself as one — no underline, no colour change, the
   same ink as the words around it. Pointing at it is what reveals it: the whole line takes a
   fraction of a degree of tilt and a few percent of scale, as if it had been written on a page that
   is not quite square. transform-origin is at the left so it grows away from the margin, and a
   transform costs no layout, so the ruling underneath does not move.

   The 180ms ease is a deliberate FOURTH deviation from /pastel, which wants chrome to snap: a
   scale-and-tilt that teleports reads as a glitch rather than as a nudge. It is the only eased
   transition in the file, and it is not on chrome — it is on the owner's own signature. */
.doodle a{color:inherit;text-decoration:none;display:inline-block;
  transform-origin:left center;transition:transform .18s ease-out}
.doodle a:hover{transform:scale(1.035) rotate(-0.8deg)}
@media(prefers-reduced-motion:reduce){.doodle a{transition:none}.doodle a:hover{transform:none}}

/* ---------- 5. btn — THE ONLY FILLED SHAPE ON THE SITE (LAW-1) ---------- */
.btn,button{
  display:inline-block;font:inherit;cursor:pointer;
  border:3px solid var(--ink);border-radius:var(--r);
  background:var(--accent-faint);color:var(--ink);
  padding:11px 15px;line-height:var(--pitch);
  font-size:11px;letter-spacing:1.6px;text-transform:uppercase;
  box-shadow:3px 3px 0 var(--ink);
}
.btn:hover,button:hover{background:var(--accent-soft)}
/* press-into-shadow physics — the signature tactile trick, instant, never eased */
.btn:active,button:active{transform:translate(3px,3px);box-shadow:0 0 0}
.btn.on,button.on{background:var(--accent);color:var(--paper)}
.btn.go{background:var(--accent);color:var(--paper)}
.btn.go:hover{background:var(--accent-dark)}
.btn.wide{display:block;width:100%;text-align:center;padding:25px 15px;font-size:13px;letter-spacing:3px}  /* 84px = 3 pitches */
.form .btn.wide{margin:0 0 var(--pitch)}
.btn.red{background:var(--danger);color:var(--paper)}
.btn.red:hover{background:#9E2E25}
.btn.red.wide{margin-top:var(--pitch)}
.btn.yes,button.yes{background:var(--good);color:var(--paper)}
.btn.yes:hover,button.yes:hover{background:#33654A}
.btn.no,button.no{background:var(--danger);color:var(--paper)}
.btn.no:hover,button.no:hover{background:#9E2E25}

/* ---------- 6. field — outline only, no card wrapper ----------
   Labels are in pencil; what you write is in ink. */
.field{display:block;margin:0 0 var(--pitch)}
.field > span{display:block;height:var(--pitch);margin:0;font-size:10px;letter-spacing:2px;
  line-height:var(--pitch);text-transform:uppercase;color:var(--pencil)}
.field input:not([hidden]),.field textarea{
  width:100%;font:inherit;color:var(--ink);
  border:2px solid var(--accent-soft);border-radius:var(--r);
  /* 2 + 26 + 28 + 26 + 2 = 84px = 3 pitches. The 26 is not arbitrary: border + padding has to be
     a WHOLE pitch or everything typed inside starts off the ruling (it was 14px out at padding 12).
     display:block matters too — an inline-block control carries a baseline descender gap underneath
     it, which pushed the field 10px past a whole pitch. */
  /* :not([hidden]) is load-bearing — a bare display:block beats the hidden attribute and the
     file input starts laying out an invisible 84px box inside the drop area. */
  display:block;padding:26px 12px;line-height:var(--pitch);outline:none;
}
.field textarea{min-height:420px;resize:vertical}   /* 15 pitches: 56 of chrome + 13 written lines.
     Bigger than it was because a whole pitch of chrome costs 28px more than the old padding did,
     and the hint wraps to 11 lines at phone width. */
.field input:focus,.field textarea:focus{border-color:var(--accent)}
/* the hint is pencilled in, and rubs out the moment anyone writes over it */
.field input::placeholder,.field textarea::placeholder{color:var(--pencil-soft);opacity:1}
/* the border IS the message — an empty required field is never explained in words */
.field.bad input,.field.bad textarea,.field.bad .drop{border-color:var(--danger-faint)}
/* an outline, not a border: .chips must stay exactly one pitch tall and a border would add to it */
.field.bad .chips{outline:2px solid var(--danger-faint);outline-offset:3px;border-radius:var(--r)}

/* ---------- 7. drop — the upload area and its three states ---------- */
.drop{
  position:relative;display:block;cursor:pointer;
  border:2px solid var(--danger-faint);border-radius:var(--r);
  min-height:168px;padding:26px;              /* 6 pitches; 2 + 26 = 28 of chrome */
  text-align:center;color:var(--pencil);
  font-size:10px;letter-spacing:2px;text-transform:uppercase;
}
.drop[data-state="busy"]{border-color:var(--warn)}
.drop[data-state="done"]{border-color:var(--good)}
.drop.over{border-color:var(--accent)}
.drop u{display:block;text-decoration:none;font-size:26px;line-height:var(--pitch);margin:var(--pitch) 0 0;color:var(--pencil-soft)}
.drop em{display:block;font-style:normal;height:var(--pitch);line-height:var(--pitch);margin:0;
  color:var(--good);font-size:10px;letter-spacing:2px}
.drop .shots{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-top:var(--pitch)}
.drop .shots:empty{display:none}   /* an empty row must not spend a margin */
.drop .shots img{width:62px;height:62px;object-fit:cover;
  border:2px solid var(--ink);border-radius:var(--r)}

/* ---------- 8. ring — the circling green loader ----------
   Parked in the corner, not the middle: centred it collided with the "+" affordance and with the
   thumbnails as they arrived. 50% radius is the one exception to the 6px cap: a circle is a circle. */
.ring{
  position:absolute;right:12px;top:12px;width:26px;height:26px;
  border:3px solid var(--accent-faint);border-top-color:var(--good);border-radius:50%;
  animation:spin .75s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- 9. chip — the stage, as a choice and as a label ----------
   stage opens the form, and it is centred — the only centred field on the page. Targeted by the
   data-key rather than a new class, so the component vocabulary does not grow. */
.chips{position:relative;display:flex;flex-wrap:wrap;gap:8px;justify-content:center;height:var(--pitch)}
.field[data-k="stage"]{margin-bottom:var(--pitch)}
.field[data-k="stage"] > span{text-align:center}
.chip{
  border:2px solid var(--accent-soft);border-radius:var(--r);
  padding:0 11px;height:var(--pitch);line-height:24px;font-size:10px;letter-spacing:1.6px;
  text-transform:uppercase;color:var(--accent-dark);
}
/* a selectable chip is a button, so under LAW-1 it may be filled */
button.chip{box-shadow:2px 2px 0 var(--ink);border-color:var(--ink);background:transparent}
button.chip:hover{background:var(--accent-faint)}
button.chip.on{background:var(--accent);color:var(--paper);border-color:var(--ink)}

/* The hover explanation. Drawn entirely by CSS from the chip's own data-tip — no element, no script,
   and nothing on the page until someone points at a chip.

   It is anchored to .chips, NOT to the chip, and stretches the full width of the row. Anchored to
   the chip it would be centred on SCRAP or on READY and hang off the edge of the wrap, which is a
   horizontal scrollbar the sweep would (correctly) fail on. Full-width also means the explanation
   always appears in the same place, so reading across the five stages does not make it jump.

   --paper with an ink outline, not a fill: it has to be opaque to sit legibly over the ruled lines,
   and paper-on-paper is still a cut-out rather than a card under LAW-1. */
.chip::after{
  content:attr(data-tip);
  position:absolute;left:0;right:0;top:calc(100% + 12px);z-index:5;
  display:none;
  padding:11px 14px;
  border:3px solid var(--ink);border-radius:var(--r);
  background:var(--paper);
  box-shadow:4px 4px 0 var(--accent-soft);
  font-size:11px;line-height:var(--pitch);letter-spacing:.4px;
  text-transform:none;text-align:center;color:var(--ink);
}
.chip:hover::after,.chip:focus-visible::after{display:block}

/* ---------- 10. band — pending / type, outline only ---------- */
.band{
  border:3px dashed var(--warn);border-radius:var(--r);
  padding:25px 16px;margin:0 0 var(--pitch);   /* 3 + 25 = 28 of chrome, 84px = 3 pitches */
  font-size:11px;letter-spacing:3px;text-transform:uppercase;color:var(--pencil);
}
.band.t{display:inline-block;margin:0;padding:0 10px;height:var(--pitch);line-height:24px;border-style:solid;
  border-color:var(--accent);color:var(--accent-dark);letter-spacing:2px}
.band.t.re{border-color:var(--danger);color:var(--danger)}

/* ---------- 11. row — one pending record in the hub ---------- */
.row{border:3px solid var(--ink);border-radius:var(--r);padding:25px 16px;margin:0 0 var(--gap)}
/* 3 + 25 = 28: one whole pitch of chrome, so the writing inside starts back on the ruling */
.row h2{margin:0;font-size:17px;line-height:var(--pitch);letter-spacing:.4px;
  padding:27px 0 1px}   /* 2 pitches — a blank rule, then the heading on the next one */
.row p{margin:0;font-size:12px;line-height:var(--pitch);color:var(--pencil)}
.row .shots{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 var(--pitch)}
.row .shots img{width:84px;height:84px;object-fit:cover;border:2px solid var(--ink);border-radius:var(--r)}   /* 3 pitches */
.row .acts{display:flex;gap:10px;margin:0}
.row .acts button{font-size:15px;padding:11px 22px;line-height:var(--pitch)}
.row p a{color:var(--accent-dark);border-bottom:2px solid var(--accent-soft)}
.row .band.t + .band.t{margin-left:8px}

/* ---------- 12. sheet — the display page, and the surface that flips ---------- */
.sheet{display:block;margin:0 auto;
  transform-origin:left center;backface-visibility:hidden}
.sheet h1{margin:0;font-size:30px;line-height:56px;letter-spacing:-.3px;
  padding:9px 0 19px}   /* 3 pitches — the padding is what puts a 30px baseline ON a rule */
.sheet .by{height:var(--pitch);margin:0 0 var(--pitch);
  font-size:11px;letter-spacing:2px;text-transform:uppercase;color:var(--pencil)}
.sheet .by .chip{margin-left:8px;vertical-align:top}
.sheet .shots{display:flex;flex-direction:column;gap:var(--pitch);margin:0 0 var(--pitch)}
.sheet .shots img{width:100%;border:3px solid var(--ink);border-radius:var(--r)}
.sheet .body{margin:0 0 var(--pitch);font-size:14px;line-height:var(--pitch);white-space:pre-wrap}
.sheet .foot{display:flex;align-items:center;justify-content:center;gap:16px;margin:0 0 var(--pitch)}
.sheet .foot button{box-shadow:2px 2px 0 var(--ink);padding:11px 14px}
.sheet .foot button[disabled]{opacity:.35;cursor:default;box-shadow:none}
.sheet .pips{height:var(--pitch);line-height:var(--pitch);font-size:10px;letter-spacing:2px;
  text-transform:uppercase;color:var(--pencil)}
.paged .wrap{perspective:2200px;max-width:760px}

/* ---------- 13. trail — the path the reader took ----------
   Ink links on the ruling, oldest first. One pitch tall, so it costs the page exactly one line. */
.trail{height:var(--pitch);line-height:var(--pitch);overflow:hidden;white-space:nowrap;
  font-size:11px;letter-spacing:1.4px;text-transform:uppercase}
.trail:empty{display:none}
.trail a{color:var(--accent);text-decoration:underline;text-underline-offset:5px}
.trail a:hover{color:var(--accent-dark)}
.trail a[aria-current]{color:var(--pencil);text-decoration:none}
.trail b,.trail i{font-weight:400;font-style:normal;color:var(--pencil-soft);margin:0 8px}

/* ---------- 13. turn — the page that bends ----------
   A fixed layer of N strips, each a window onto the outgoing page, each rotating a few frames
   behind the one before it. That lag across the sheet is the curl; one element rotating alone is a
   slab. The back face is blank ruled paper, because that is what the back of a page is. */
.turn{position:fixed;inset:0;perspective:2400px;pointer-events:none;z-index:50}
.turn > *{
  position:absolute;overflow:hidden;
  transform-style:preserve-3d;backface-visibility:hidden;will-change:transform;
  background-color:var(--paper);
  background-image:repeating-linear-gradient(to bottom, transparent 0, transparent 27px, var(--rule) 27px, var(--rule) 28px);
  background-attachment:local;
}
@media(prefers-reduced-motion:reduce){.turn{display:none}}
.flip{animation:pageflip .85s cubic-bezier(.42,0,.3,1) both}
@keyframes pageflip{
  0%{transform:rotateY(-88deg)}
  55%{transform:rotateY(-24deg)}
  100%{transform:rotateY(0deg)}
}
@media(prefers-reduced-motion:reduce){.flip{animation-duration:.01ms}.ring{animation-duration:2s}}

/* ---------- 16. stamp — the chimp, pressed into the foot of the page ----------
   It replaces the top-left mark, and carries the navigation the mark used to: it is the way home.
   Right-aligned by an auto left margin rather than a float or a position, so it stays in the flow
   and its 168px (six ruled lines) keeps the page on the grid. The tilt is a transform, which costs
   no layout — a stamp is never pressed straight. */
.stamp{
  display:block;margin:var(--pitch) 0 0 auto;
  width:168px;height:168px;position:relative;
  color:var(--ink);
  transform:rotate(-8deg);opacity:.82;
}
.stamp svg{display:block;width:100%;height:100%}
.stamp img{
  /* 128px is the chimp's NATIVE size — drawn 1:1 it is pixel-exact, and it fills the ring
     (inner diameter about 156px) with just a rim of paper showing. */
  position:absolute;left:50%;top:50%;width:128px;height:128px;margin:-64px 0 0 -64px;
  image-rendering:pixelated;opacity:.88;
}
.stamp:hover{opacity:1}
