/* swox — global stylesheet
   tokens, typography, links, shared elements.
   Homepage-only layout lives in home.css. */

:root {
  --bg:     #111212;
  --text:   #EFECE1;
  --red:    #E63946;
  --blue:   #3067D2;
  --green:  #749F40;

  /* Readability tint. --blue (#3067D2) is only ~3.6:1 on --bg, which fails
     for body text at Gaegu's stroke weight. Use --blue for large accents,
     --blue-text (~5.2:1) for inline links. Borders and dividers used to take
     --blue too, which left the blog and the admin looking like grids of blue
     boxes with blue links inside them; that job now belongs to the hairline
     greys below, so blue reads as "link".
     If the palette is ever cut back to three colors, delete this one line. */
  --blue-text: #5985DB;

  /* Surfaces and hairlines. Structure — borders, dividers, rows, panels — is
     drawn in these warm greys so it stops competing with the palette: red,
     green and blue are then free to mean something. The admin and the blog
     both build on this set; the admin adds an amber accent of its own. */
  --panel:   #191B1A;  /* raised surface */
  --sunk:    #131514;  /* recessed surface */
  --line:    #33322C;  /* hairline */
  --line-2:  #4A473E;  /* stronger edge */
  --muted:   #9C968A;  /* warm grey text */
  --ink:     rgba(0, 0, 0, 0.5); /* hard pixel shadow, never blurred */

  /* Graph paper. The admin re-tints --grid-line amber; that is the only
     place on the site where the ground changes. */
  --grid-line: rgba(239, 236, 225, 0.055);
  --grid-size: 34px;
}

/* ---------- reset-ish ---------- */

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scrollbar-color: var(--green) var(--bg);
  /* Reserve the scrollbar gutter on BOTH edges. Without this the scrollbar
     eats width only on the right, so the centred wrapper sits half a
     scrollbar-width left of the true window centre. */
  scrollbar-gutter: stable both-edges;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  /* Gaegu renders small for its point size — 21px, not 16px. */
  font-family: "Gaegu", "Comic Sans MS", cursive, sans-serif;
  font-size: 19px;
  line-height: 1.5;
}

/* ---------- structure ---------- */

wrapper {
  display: block; /* required: custom elements have no default display */
  max-width: 800px;
  margin: 20px auto;
}

@media (max-width: 700px) {
  wrapper { margin: 20px; }
}

/* ---------- graph paper ---------- */

/* Drawn with gradients rather than a tiled image, so there is no asset to load
   and the lines can be tuned for the dark palette. Kept faint: body copy sits
   directly on top of it and has to stay comfortably readable. It started as a
   blog-only background in blue; one ground under the whole site, in cream, is
   both quieter and consistent. */
body {
  /* A background repeats across its own positioning area — the element's box,
     not the window. On a page with little in it the body is shorter than the
     screen, so the tile is short too and the grid starts over partway down:
     a band where the rhythm breaks and the squares below stop lining up with
     the ones above. The notes lock screen showed it worst, at 282px against
     an 800px window, but the todo lock screen and the 404 do it too.

     A floor of one screen makes the tile at least as tall as anything you can
     see, so only one of it is ever on screen and there is no seam to find.

     flow-root belongs with it rather than being tidiness: without a block
     formatting context the wrapper's 20px top margin collapses out through
     the body, which would carry that floor 20px past the bottom of the window
     and hand every short page a scrollbar it has no use for. Nothing moves —
     the margin is kept inside the body instead of escaping it. */
  /* dvh where it exists, the same pair /dc/'s window (.dc) uses: on a phone the
     toolbars slide away and 100vh does not notice, which would put the floor
     below the window and bring back the scrollbar this is removing. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flow-root;

  background-image:
    repeating-linear-gradient(
      to right,
      var(--grid-line) 0 1px,
      transparent 1px var(--grid-size)
    ),
    repeating-linear-gradient(
      to bottom,
      var(--grid-line) 0 1px,
      transparent 1px var(--grid-size)
    );
}

@media (prefers-contrast: more) {
  :root { --grid-line: transparent; }
}

/* ---------- two-column pages ---------- */

/* The homepage and the admin are the same shape: a full-width header over a
   wide content column and a narrow nav. That layout used to live twice, once
   in each of their stylesheets, and had already drifted apart — different
   gaps. It lives here now; both pages opt in with `bodyClass: sidebar`. */
.sidebar main {
  display: grid;
  grid-template-areas:
    "header header"
    "content nav";
  grid-template-columns: 4fr 1.5fr;
  gap: 26px;
}

.sidebar header   { grid-area: header; }
.sidebar #content { grid-area: content; }
.sidebar nav      { grid-area: nav; }

@media (max-width: 700px) {
  .sidebar main {
    grid-template-areas:
      "header"
      "content"
      "nav";
    grid-template-columns: 1fr;
  }
}

/* ---------- section headings ---------- */

/* A block marker and a dashed rule under every section title on those two
   pages. The shape is shared; each stylesheet picks its own marker colours. */
.sidebar #content h2,
.sidebar nav h2,
.sidebar nav h3 {
  margin: 28px 0 14px;
  padding-bottom: 8px;
  border-bottom: 1px dashed var(--line);
}

.sidebar #content h2:first-child,
.sidebar nav h2:first-child,
.sidebar nav h3:first-child {
  margin-top: 0;
}

.sidebar #content h2::before,
.sidebar nav h2::before,
.sidebar nav h3::before {
  content: "\258D";
  margin-right: 8px;
}

/* ---------- sidebar nav ---------- */

/* A panel, and a chip per link: the bar on the left takes the link's own
   colour, which is where the red/blue/green cycle pays off. Both pages kept
   their own copy of that cycle; this is the one copy. */
.sidebar nav {
  display: flex;
  flex-direction: column;
  padding: 16px 18px;
  background: var(--panel);
  border: 2px solid var(--line-2);
  box-shadow: 6px 6px 0 var(--ink);
}

.sidebar nav ul {
  list-style: none;
  padding-left: 0;
  margin: 10px 0 0;
}

.sidebar nav li { margin: 3px 0; }

.sidebar nav li a {
  display: block;
  padding: 3px 8px;
  border-left: 3px solid transparent;
  text-decoration: none;
}

.sidebar nav li a:hover,
.sidebar nav li a:focus-visible {
  background: var(--sunk);
  border-left-color: currentColor;
}

/* Each list cycles red -> blue -> green independently. */
.sidebar nav li:nth-of-type(3n+1) a { color: var(--red); }
.sidebar nav li:nth-of-type(3n+2) a { color: var(--blue-text); }
.sidebar nav li:nth-of-type(3n+3) a { color: var(--green); }

/* ---------- typography ---------- */

/* Press Start 2P is very wide, ships one weight, and has no lowercase
   descender variation. Size everything with clamp() and keep line-height
   generous or headings overflow the 800px wrapper. */
h1, h2, h3, h4, h5, h6 {
  font-family: "Press Start 2P", "Courier New", monospace;
  font-weight: 400;   /* never bold: no bold cut exists, browsers fake a smear */
  letter-spacing: 0;  /* never raise: the face is already very open */
  color: var(--text);
}

h1 { font-size: clamp(0.85rem, 3.6vw, 1.5rem);  line-height: 1.9; }
h2 { font-size: clamp(0.75rem, 2.6vw, 1.05rem); line-height: 1.8; }
h3 { font-size: clamp(0.7rem,  2.2vw, 0.9rem);  line-height: 1.8; }
h4, h5, h6 { font-size: clamp(0.65rem, 2vw, 0.85rem); line-height: 1.8; }

/* Gaegu's line-through sits at the wrong y-position; draw it manually. */
s, del {
  text-decoration: none;
  background-image: linear-gradient(
    transparent 45%, currentColor 45%, currentColor 56%, transparent 56%
  );
}

/* ---------- images ---------- */

/* Safety net: nothing may render wider than its container. Post images get
   richer treatment under "pictures" below, but this catches anything that
   is not wrapped in a figure. */
img {
  max-width: 100%;
  height: auto;
}

/* ---------- links ---------- */

a { color: var(--blue-text); }
a:hover { text-decoration: none; }

/* Every off-site link gets a superscript arrow. */
a[href^="http"]::after {
  content: " \2197";
  font-size: 0.83rem;
  vertical-align: super;
}

/* ---------- lists ---------- */

li { margin: 5px; }

/* ---------- breadcrumb ---------- */

/* Chrome, wherever it appears: one size down from the body, in the grey the
   separators use, with the links inside it still carrying the colour. */
.breadcrumb {
  margin: -6px 0 18px;
  font-size: 1rem;
  color: var(--muted);
}

/* Every page title outside the two-column pages takes a block marker — green,
   matching the breadcrumb's you-are-here segment. (The homepage and the admin
   put their h1 inside a <header>, so this cannot reach them.) */
main > h1::before {
  content: "\258D";
  margin-right: 10px;
  color: var(--green);
}

/* ---------- tiles ---------- */

/* A list of short labels — years, months, the sitemap — as pressable tiles
   rather than bullets: the admin's chunky square button, down to the shadow
   that collapses when you push it. */
.tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  list-style: none;
  padding-left: 0;
  margin: 24px 0;
}

.tiles > li { margin: 0; }

.tiles > li > a {
  display: block;
  padding: 6px 20px;
  color: var(--text);
  text-decoration: none;
  background: var(--panel);
  border: 2px solid var(--line-2);
  box-shadow: 3px 3px 0 var(--ink);
  transition: color .12s, border-color .12s, transform .06s, box-shadow .06s;
}

/* Cycles the site's three colours the way the nav does. */
.tiles > li:nth-child(3n+1) > a:hover,
.tiles > li:nth-child(3n+1) > a:focus-visible { color: var(--red); border-color: var(--red); }
.tiles > li:nth-child(3n+2) > a:hover,
.tiles > li:nth-child(3n+2) > a:focus-visible { color: var(--blue-text); border-color: var(--blue-text); }
.tiles > li:nth-child(3n+3) > a:hover,
.tiles > li:nth-child(3n+3) > a:focus-visible { color: var(--green); border-color: var(--green); }

.tiles > li > a:active {
  transform: translate(3px, 3px);
  box-shadow: 0 0 0 var(--ink);
}

/* A divider, not a link — it takes the hairline grey, not the link blue. */
.breadcrumb .sep {
  color: var(--line-2);
  padding: 0 2px;
}

.breadcrumb [aria-current="page"] {
  color: var(--green);
}

/* ---------- collapsibles ---------- */

/* One entry card, used by the month archive and by "latest blogs" on the
   homepage. It is the same markup in both places, so it gets one look. The
   blue outline it used to wear was the same colour as the link inside it;
   the bar down the left carries the state instead. */
details {
  margin: 10px 0;
  padding: 10px 14px;
  background: var(--sunk);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-2);
  transition: background-color .12s, border-color .12s;
}

details:hover  { border-left-color: var(--green); }
details[open] {
  background: var(--panel);
  border-left-color: var(--green);
}

/* The date and the dash around the title are chrome; the title stays a link.
   The disclosure triangle is the browser's, not the site's, so it is replaced
   with one that opens and closes in the palette. */
summary {
  color: var(--muted);
  list-style: none;
}

summary::-webkit-details-marker { display: none; }

summary::before {
  content: "\25B8";
  display: inline-block;
  width: 1.1em;
  color: var(--green);
}

details[open] > summary::before { content: "\25BE"; }

details p {
  margin: 8px 0 2px 1.1em;
  color: var(--muted);
}

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

footer {
  text-align: center;
  border: none;
  margin-top: 40px;
}

.star { color: var(--green); }

/* ---------- cursors ---------- */

button,
abbr[title],
img[title] {
  cursor: help;
}

/* The disclosure control is a button, so it takes the hand. Cannot be scoped
   to just the marker triangle: ::marker accepts only a small set of font and
   colour properties, and cursor is not one of them. The whole summary row is
   the click target anyway. */
summary {
  cursor: pointer;
}

/* Custom pixel cursor — enable once /_files/img/cursor.png exists.
   Needs a 32x32 (max) PNG with the hotspot at top-left.
   Always keep the `auto` fallback: browsers reject oversized cursor images silently.

body {
  cursor: url(/_files/img/cursor.png) 0 0, auto;
}
a:hover, button:hover {
  cursor: url(/_files/img/cursor-pointer.png) 0 0, pointer;
}
*/

/* ---------- pictures ---------- */

.post-image {
  margin: 26px 0;
  text-align: center;
}

/* Hugs the image, and carries the frame: a hairline edge and the same hard,
   unblurred shadow the panels use, so a photo sits on the page like something
   placed there rather than pasted in. */
.post-image-frame {
  display: inline-block;
  max-width: 100%;
  line-height: 0;
  border: 1px solid var(--line-2);
  box-shadow: 5px 5px 0 var(--ink);
}

/* A lone image: bounded on BOTH axes with auto on the other, so a wide photo
   never overflows the column and a tall one never runs off the screen. Aspect
   ratio is preserved either way. */
.post-image-frame img {
  display: block;
  max-width: 100%;
  max-height: 78vh;
  width: auto;
  height: auto;
}

/* Was --blue-text, which made every caption look like a link. */
.post-image figcaption {
  margin-top: 10px;
  font-size: 1rem;
  line-height: 1.4;
  color: var(--muted);
}

/* ---------- galleries ---------- */

/* Images pack into columns. CSS multi-column produces the same result
   masonry.js does — items flow into columns and stack tight regardless of
   differing heights — without a layout library, a JS layout pass, or the
   reflow you get when images finish loading.

   Two variants: a run of images inside a post, and the photos page. They
   differ only in how many fit across. */
.post-gallery,
.photo-gallery {
  margin: 26px 0;
  column-gap: 18px; /* room for the frame shadow between columns */
}

.post-gallery { column-count: 3; }

.photo-gallery { column-count: 3; }

.post-gallery .post-image,
.photo-gallery .post-image {
  margin: 0 0 18px;
  /* Keeps a figure from being split across two columns. */
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  /* block, not inline-block: as inline-level boxes the figures would not be
     distributed across the columns at all — a gallery of two sat one on top
     of the other in the first column with the second empty. */
  display: block;
  width: 100%;
}

.post-gallery .post-image-frame,
.photo-gallery .post-image-frame {
  display: block;
  box-shadow: 3px 3px 0 var(--ink);
}

/* Inside a gallery the image fills its column and keeps natural height — that
   uneven height is what makes the packing read as a scrapbook rather than a
   grid of boxes. */
.post-gallery .post-image-frame img,
.photo-gallery .post-image-frame img {
  width: 100%;
  max-width: 100%;
  max-height: none;
  /* auto against the width/height attributes keeps the aspect ratio, and lets
     the browser hold the right amount of space before a lazy picture loads */
  height: auto;
}

@media (max-width: 700px) {
  .post-gallery,
  .photo-gallery { column-count: 1; }
}

/* Grain is burned into the image files themselves at upload (see the grain
   control in the admin), so there is deliberately no CSS grain overlay here —
   one on top of the other would double it. */

/* ---------- post masthead ---------- */

/* The stamp and the post's one-line description sit under the title, closed
   off from the body by the same dashed rule the admin runs under its section
   headings.

   Keyed on a class rather than "the paragraph after the h1", which is what it
   used to be: on a private post the byline is built inside an <article> after
   unlocking, so the positional rule never reached it and that page alone came
   out without its rule. */
.post-head {
  margin: -6px 0 22px;
  padding-bottom: 14px;
  font-size: 1rem;
  color: var(--muted);
  border-bottom: 1px dashed var(--line);
}

.post-head p {
  margin: 4px 0;
}

/* ---------- microblogs ---------- */

/* A feed, not a list of pages: the stamp and the line run together, and a
   dashed rule keeps one entry from bleeding into the next. The markers cycle
   the site's three colours the way the nav does. */
.micro-feed {
  margin: 24px 0;
}

.micro {
  margin: 0;
  padding: 14px 0;
  border-bottom: 1px dashed var(--line);
}

.micro:first-child { padding-top: 4px; }
.micro:last-child  { border-bottom: none; }

.micro::before {
  content: "\258D";
  margin-right: 8px;
}

.micro:nth-child(3n+1)::before { color: var(--red); }
.micro:nth-child(3n+2)::before { color: var(--blue); }
.micro:nth-child(3n+3)::before { color: var(--green); }

/* The moment, not a link — grey, and never broken across lines. */
.micro-stamp {
  color: var(--muted);
  white-space: nowrap;
}

/* On the homepage the whole line is a link to the feed. It keeps the body
   colour rather than the link blue: a paragraph of blue text would read as a
   mistake, and the marker lighting up on hover says it is clickable. */
.micro-link {
  display: block;
  color: var(--text);
  text-decoration: none;
}

.micro-link:hover,
.micro-link:focus-visible {
  background: var(--sunk);
}

.micro-link:hover .micro-stamp,
.micro-link:focus-visible .micro-stamp {
  color: var(--text);
}

/* The two ways out of the homepage's content column: back through the blog on
   one side, on through the feed on the other. */
.content-links {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 20px;
  justify-content: space-between;
}

/* ---------- pager ---------- */

/* Paging through a feed: a step at each end and the numbers between them.
   Only five numbers show at once, with the first and last page always
   reachable, so a long feed does not grow a row of forty buttons.

   Built out of links, not buttons — every page has a real address, and the
   whole thing works with no script at all. The step at an end you cannot go
   past stays in place as dead text rather than disappearing, so the numbers
   do not slide sideways as you move through the feed. */
.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 30px 0 10px;
  padding-top: 20px;
  border-top: 1px dashed var(--line);
}

.pager-nums {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 5px;
}

.pager-step,
.pager-num {
  display: inline-block;
  padding: 3px 14px;
  color: var(--muted);
  text-decoration: none;
  background: var(--panel);
  border: 2px solid var(--line-2);
  box-shadow: 3px 3px 0 var(--ink);
  transition: color .12s, border-color .12s, transform .06s, box-shadow .06s;
}

.pager-num {
  min-width: 2.4em;
  padding: 3px 8px;
  text-align: center;
}

a.pager-step:hover,
a.pager-num:hover {
  color: var(--green);
  border-color: var(--green);
}

a.pager-step:active,
a.pager-num:active {
  transform: translate(3px, 3px);
  box-shadow: 0 0 0 var(--ink);
}

/* The page you are on. Same fill the todo board's chips use for a chosen
   one: it is a state, not a link, so it does not get the link colour. */
.pager-num.on {
  color: var(--bg);
  background: var(--text);
  border-color: var(--text);
}

/* prev on page one, next on the last. */
.pager-step.is-off {
  color: var(--line-2);
  background: var(--sunk);
  border-color: var(--line);
  box-shadow: none;
}

.pager-gap {
  padding: 0 2px;
  color: var(--muted);
}

.pager-count {
  margin: 0;
  text-align: center;
}

@media (max-width: 560px) {
  /* The steps take a line of their own so the numbers keep their row. */
  .pager {
    flex-wrap: wrap;
  }

  .pager-nums {
    order: -1;
    flex-basis: 100%;
  }

  .pager-step {
    flex: 1 1 auto;
    text-align: center;
  }
}

/* ---------- 404 ---------- */

/* The mascot again, at the size the favicon is drawn for. It has a real alpha
   channel, so it sits on the paper with no matte — the same reason the
   homepage one carries no border. */
.notfound {
  display: flex;
  gap: 22px;
  align-items: center;
  margin: 26px 0 30px;
}

.notfound p {
  margin: 0;
}

.notfound-mark {
  flex: 0 0 auto;
  width: 140px;
  height: auto;
  /* Pixel art: without this it goes soft at any size but its own. */
  image-rendering: pixelated;
}

/* Not a location you are at — a wrong turn. */
.notfound-title::before { color: var(--red); }

@media (max-width: 700px) {
  .notfound {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ---------- sorting the photos ---------- */

/* One control, so it sits on the line rather than announcing itself. */
.photo-sort {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin: 20px 0 0;
}

.photo-sort label {
  font-family: "Press Start 2P", "Courier New", monospace;
  font-size: 0.62rem;
  color: var(--muted);
}

.photo-sort select {
  width: auto;
  max-width: 100%;
}

/* Reads as the order you are looking at, not the one you would get. */
.photo-sort button {
  padding: 3px 14px;
}

/* ---------- zoom ---------- */

/* A framed picture is always smaller than the file behind it — scaled to its
   column in a gallery, to the page everywhere else. Clicking one puts the
   whole thing on screen. */
.post-image-frame img {
  cursor: zoom-in;
}

.zoom-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(9, 10, 10, 0.975); /* opaque enough that page text does not read through */
  cursor: zoom-out;
}

.zoom-backdrop[hidden] { display: none; }

.zoom-backdrop img {
  max-width: 95vw;
  max-height: 86vh;
  width: auto;
  height: auto;
  border: 1px solid var(--line-2);
  box-shadow: 6px 6px 0 var(--ink);
}

.zoom-caption {
  margin: 0;
  max-width: 46em;
  font-size: 1rem;
  line-height: 1.4;
  text-align: center;
  color: var(--muted);
}

/* Nothing scrolls behind the overlay. */
body.zoomed { overflow: hidden; }

/* ---------- form controls ---------- */

/* One definition of what a field and a button look like, shared by the admin
   and by the gate on a private post. Square, warm-edged, and — for buttons —
   chunky, with a hard shadow that collapses when you press them. The admin
   re-colours these for its own roles: green saves, red destroys, amber is its
   chrome. This is also where a button stops taking the site-wide help cursor;
   a real control gets a real pointer. */

.field {
  display: block;
  margin: 16px 0;
}

/* Labels in the pixel face read as instrument legends and tie a form to the
   site's headings. Lowercase, like everything else here. */
.field label {
  display: block;
  margin-bottom: 6px;
  font-family: "Press Start 2P", "Courier New", monospace;
  font-size: 0.62rem;
  line-height: 1.6;
  color: var(--muted);
}

input,
textarea,
select {
  width: 100%;
  font: inherit;
  color: var(--text);
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: 0; /* square: the site is set in a pixel face */
  padding: 5px 10px;
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.45);
}

input::placeholder { color: #6B665D; }

input:hover,
textarea:hover,
select:hover {
  border-color: var(--line-2);
}

input:focus,
textarea:focus,
select:focus {
  border-color: var(--green);
  box-shadow: inset 0 -2px 0 var(--green);
}

textarea {
  min-height: 4.5em;
  resize: vertical;
  scrollbar-color: var(--line-2) var(--sunk);
}

button {
  font: inherit;
  color: var(--text);
  background: var(--panel);
  border: 2px solid var(--line-2);
  border-radius: 0;
  padding: 3px 16px;
  cursor: pointer;
  box-shadow: 3px 3px 0 var(--ink);
  transition: color .12s, background-color .12s, border-color .12s,
              transform .06s, box-shadow .06s;
}

button:hover {
  color: var(--green);
  border-color: var(--green);
}

button:active {
  transform: translate(3px, 3px);
  box-shadow: 0 0 0 var(--ink);
}

/* ---------- hints and status ---------- */

/* Gaegu, not the pixel face this would inherit inside a label — and one size
   down from the body, so a hint never outshouts its field. */
.hint {
  font-family: "Gaegu", "Comic Sans MS", cursive, sans-serif;
  font-size: 1rem;
  color: var(--muted);
}

.ok   { color: var(--green); }
.err  { color: var(--red); }

/* A glyph so the result reads before the colour does. :not(:empty) keeps it
   off the message lines while they are still blank. */
.ok:not(:empty)::before  { content: "\2713"; margin-right: 0.4em; }
.err:not(:empty)::before { content: "\2715"; margin-right: 0.4em; }

/* ---------- locked card ---------- */

/* Used twice: the admin's password gate, and the gate on a private post. A
   hazard strip pulled edge to edge across the top of a small card — it is the
   first thing anyone sees in both places, so it gets to look like something. */
.locked {
  max-width: 26em;
  padding: 16px 18px;
  background: var(--panel);
  border: 2px solid var(--line-2);
  box-shadow: 6px 6px 0 var(--ink);
}

.locked::before {
  content: "";
  display: block;
  height: 10px;
  margin: -16px -18px 16px;
  opacity: 0.5;
  background: repeating-linear-gradient(
    45deg, var(--red) 0 6px, transparent 6px 12px
  );
}

/* On a private post the page title is a warning, not a location, so its
   marker is red rather than the usual you-are-here green. */
.locked-title::before { color: var(--red); }

/* ---------- misc ---------- */

::selection {
  background: var(--red);
  color: var(--text);
}

:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 2px;
}

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