/* ---------------------------------------------------------------- tokens
   The whole palette in one place, calibrated against the locked north star
   (reference/northstar/, JUDGING.md): one wall, one paper, everywhere.
   Wall green targets ~#2E4237 — deep NYC hunter green, faint blue
   undertone, between the two reference photos' weathering envelope.
   Textures are shared grayscale relief maps (mean 0.5) — always paired
   with soft-light, never multiply. */

:root {
  /* wall — painted once, weathered together: ONE green for every view */
  --wall-paint: #2e4237;
  --wall-paint-hi: #33483c;
  --wall-vignette: rgba(10, 16, 13, 0.28);
  --seam-gap: rgba(4, 8, 6, 0.68);
  --seam-lit: rgba(255, 255, 255, 0.07);

  /* paper & ink — ONE cream stock sitewide (north-star home-desktop) */
  --paper: #ede5d3;
  --paper-deep: #e2d9c4;
  --ink: #26221b;
  --ink-soft: #55503f;
  /* faint ink still has to clear WCAG AA at small-print sizes on BOTH
     paper stocks (5.1:1 on --paper, 4.5:1 on --paper-deep) */
  --ink-faint: #665f4d;
  --rule: rgba(38, 34, 27, 0.55);
  --paste-soak: rgba(96, 80, 50, 0.19);

  /* stencil-green ink for links and marks printed on paper */
  --mark: #2e5748;
  --mark-soft: rgba(46, 87, 72, 0.55);

  /* rubber-stamp ink: faded brick red, always broken by the noise mask */
  --stamp-ink: #93392c;

  /* shared texture maps — pre-tinted composites baked by
     scripts/texture/tint.mjs from the grayscale masters in
     textures/masters/. No blend mode is ever load-bearing for base
     color (Safari drops blends while re-rastering under zoom). */
  --tex-paper-a: url("/assets/paper-cream-a.webp");
  --tex-paper-b: url("/assets/paper-cream-b.webp");
  --tex-paper-c: url("/assets/paper-cream-c.webp");
  --tex-paper-deep: url("/assets/paper-deep-c.webp");
  --tex-paper: var(--tex-paper-a);
  --tex-wall: url("/assets/plywood-green.webp");
  --tex-paste-halo: url("/assets/paste-halo.webp");
  --tex-paste-scar: url("/assets/paste-scar.webp");

  /* hand-cut deckle silhouettes — mostly-straight seeded runs
     (0.2-1.1px) with occasional deeper nicks (~12% at 1.6-2.4px), so
     edges read straight at arm's length and hand-cut up close
     (generator in git history: mulberry32 seeds 11/23/47) */
  --paper-edge: polygon(
    1.0% 0.7px,
    4.0% 0.7px,
    5.6% 0.7px,
    8.1% 1.0px,
    10.6% 0.8px,
    12.4% 0.4px,
    14.9% 0.7px,
    16.6% 0.7px,
    19.1% 0.9px,
    22.5% 0.8px,
    24.5% 2.2px,
    28.5% 0.3px,
    31.8% 0.7px,
    34.7% 0.3px,
    38.3% 0.5px,
    39.8% 2.3px,
    42.5% 0.4px,
    45.2% 0.3px,
    48.3% 2.0px,
    51.3% 0.6px,
    53.9% 0.2px,
    57.2% 0.9px,
    59.4% 0.5px,
    63.0% 0.3px,
    66.1% 0.3px,
    68.4% 1.0px,
    72.0% 0.6px,
    75.8% 0.6px,
    78.0% 0.2px,
    81.7% 0.6px,
    83.4% 2.2px,
    86.2% 0.3px,
    89.1% 1.0px,
    93.0% 0.7px,
    95.9% 0.3px,
    99.0% 1.1px,
    calc(100% - 0.8px) 0.3%,
    calc(100% - 1.0px) 4.2%,
    calc(100% - 0.8px) 6.6%,
    calc(100% - 0.8px) 8.2%,
    calc(100% - 0.4px) 10.8%,
    calc(100% - 0.3px) 14.1%,
    calc(100% - 0.4px) 16.9%,
    calc(100% - 0.9px) 20.5%,
    calc(100% - 1.0px) 21.9%,
    calc(100% - 0.8px) 24.8%,
    calc(100% - 0.6px) 26.2%,
    calc(100% - 0.3px) 28.0%,
    calc(100% - 0.8px) 29.6%,
    calc(100% - 1.0px) 32.8%,
    calc(100% - 1.7px) 36.8%,
    calc(100% - 0.6px) 39.7%,
    calc(100% - 1.6px) 42.5%,
    calc(100% - 0.6px) 45.1%,
    calc(100% - 0.5px) 48.4%,
    calc(100% - 1.1px) 51.4%,
    calc(100% - 0.4px) 53.5%,
    calc(100% - 0.7px) 56.7%,
    calc(100% - 1.7px) 59.8%,
    calc(100% - 0.3px) 61.6%,
    calc(100% - 0.8px) 65.1%,
    calc(100% - 0.9px) 68.7%,
    calc(100% - 2.2px) 70.3%,
    calc(100% - 1.9px) 72.3%,
    calc(100% - 0.8px) 73.9%,
    calc(100% - 0.9px) 77.2%,
    calc(100% - 0.9px) 80.5%,
    calc(100% - 0.3px) 82.4%,
    calc(100% - 2.1px) 85.5%,
    calc(100% - 0.7px) 89.4%,
    calc(100% - 2.0px) 93.1%,
    calc(100% - 1.1px) 96.5%,
    calc(100% - 0.6px) 98.2%,
    98.0% calc(100% - 0.6px),
    95.5% calc(100% - 1.8px),
    93.8% calc(100% - 2.3px),
    91.0% calc(100% - 0.4px),
    87.2% calc(100% - 2.3px),
    85.1% calc(100% - 2.0px),
    82.7% calc(100% - 0.5px),
    80.9% calc(100% - 0.7px),
    78.3% calc(100% - 0.5px),
    75.5% calc(100% - 0.4px),
    72.8% calc(100% - 0.5px),
    70.1% calc(100% - 0.3px),
    68.1% calc(100% - 0.2px),
    66.5% calc(100% - 0.3px),
    64.5% calc(100% - 0.9px),
    61.5% calc(100% - 0.8px),
    59.2% calc(100% - 1.0px),
    56.9% calc(100% - 0.3px),
    55.2% calc(100% - 0.8px),
    53.5% calc(100% - 1.0px),
    51.8% calc(100% - 0.5px),
    48.5% calc(100% - 0.9px),
    44.6% calc(100% - 0.4px),
    42.4% calc(100% - 0.8px),
    40.8% calc(100% - 0.3px),
    38.3% calc(100% - 0.6px),
    34.5% calc(100% - 0.3px),
    32.8% calc(100% - 0.2px),
    29.0% calc(100% - 0.8px),
    26.8% calc(100% - 0.8px),
    23.4% calc(100% - 1.1px),
    20.6% calc(100% - 0.7px),
    18.2% calc(100% - 1.0px),
    16.5% calc(100% - 0.6px),
    13.4% calc(100% - 0.4px),
    10.2% calc(100% - 0.5px),
    8.6% calc(100% - 0.6px),
    6.9% calc(100% - 0.6px),
    5.0% calc(100% - 1.6px),
    2.6% calc(100% - 0.6px),
    0.7px 99.3%,
    0.7px 97.9%,
    0.8px 94.4%,
    0.3px 90.5%,
    0.4px 88.9%,
    0.3px 85.3%,
    0.9px 83.7%,
    0.2px 82.3%,
    0.6px 80.3%,
    1.6px 78.9%,
    0.2px 76.5%,
    0.4px 72.8%,
    1.7px 70.5%,
    0.9px 69.0%,
    1.0px 65.6%,
    0.8px 63.0%,
    0.6px 59.9%,
    0.6px 56.7%,
    0.5px 54.2%,
    2.1px 51.1%,
    0.4px 49.4%,
    0.4px 45.9%,
    0.5px 42.0%,
    2.3px 40.1%,
    1.0px 38.3%,
    1.0px 34.6%,
    0.5px 32.2%,
    1.6px 29.9%,
    1.8px 27.8%,
    0.4px 24.8%,
    0.9px 22.1%,
    0.6px 18.2%,
    0.5px 16.5%,
    0.4px 14.7%,
    0.4px 12.9%,
    0.2px 10.9%,
    1.9px 9.2%,
    1.1px 6.5%,
    0.5px 3.2%,
    1.0px 0.1%
  );
  --paper-edge-b: polygon(
    0.2% 2.1px,
    2.4% 0.4px,
    5.1% 0.9px,
    6.5% 0.4px,
    8.2% 1.0px,
    10.8% 0.2px,
    13.4% 1.1px,
    15.3% 0.4px,
    17.2% 0.3px,
    20.5% 0.7px,
    24.3% 1.0px,
    28.1% 0.9px,
    31.3% 0.5px,
    34.1% 1.1px,
    37.6% 0.5px,
    41.4% 0.6px,
    44.8% 0.8px,
    48.6% 0.2px,
    51.5% 0.9px,
    53.8% 0.2px,
    55.3% 0.8px,
    56.9% 1.0px,
    60.1% 0.4px,
    63.4% 0.5px,
    65.0% 0.9px,
    68.5% 0.2px,
    70.4% 0.8px,
    72.4% 0.4px,
    74.4% 1.1px,
    75.8% 0.6px,
    77.5% 0.7px,
    80.7% 0.9px,
    84.3% 0.3px,
    87.7% 0.7px,
    90.9% 0.7px,
    93.9% 0.9px,
    95.8% 0.8px,
    97.5% 1.0px,
    99.3% 0.3px,
    calc(100% - 0.7px) 0.0%,
    calc(100% - 1.0px) 2.1%,
    calc(100% - 0.7px) 3.9%,
    calc(100% - 0.6px) 5.5%,
    calc(100% - 0.2px) 8.4%,
    calc(100% - 0.6px) 10.1%,
    calc(100% - 0.3px) 12.8%,
    calc(100% - 0.4px) 16.4%,
    calc(100% - 0.5px) 19.8%,
    calc(100% - 0.6px) 21.9%,
    calc(100% - 0.3px) 24.7%,
    calc(100% - 0.5px) 26.5%,
    calc(100% - 0.9px) 29.7%,
    calc(100% - 1.0px) 31.5%,
    calc(100% - 0.3px) 34.6%,
    calc(100% - 0.9px) 37.9%,
    calc(100% - 0.7px) 41.4%,
    calc(100% - 1.0px) 44.4%,
    calc(100% - 1.7px) 46.5%,
    calc(100% - 1.1px) 50.1%,
    calc(100% - 1.0px) 52.0%,
    calc(100% - 0.4px) 54.1%,
    calc(100% - 2.3px) 57.0%,
    calc(100% - 0.6px) 59.2%,
    calc(100% - 1.0px) 60.7%,
    calc(100% - 0.6px) 63.7%,
    calc(100% - 0.6px) 66.3%,
    calc(100% - 0.6px) 69.8%,
    calc(100% - 0.6px) 72.2%,
    calc(100% - 0.4px) 74.5%,
    calc(100% - 0.9px) 77.4%,
    calc(100% - 0.4px) 79.6%,
    calc(100% - 2.4px) 81.9%,
    calc(100% - 0.8px) 84.3%,
    calc(100% - 1.0px) 88.1%,
    calc(100% - 1.9px) 90.6%,
    calc(100% - 1.6px) 92.8%,
    calc(100% - 0.9px) 94.7%,
    calc(100% - 0.9px) 98.5%,
    99.2% calc(100% - 1.0px),
    95.7% calc(100% - 0.4px),
    93.9% calc(100% - 0.7px),
    91.0% calc(100% - 2.0px),
    88.3% calc(100% - 0.4px),
    86.0% calc(100% - 0.7px),
    83.2% calc(100% - 0.9px),
    79.5% calc(100% - 2.1px),
    77.3% calc(100% - 0.7px),
    75.9% calc(100% - 0.9px),
    73.2% calc(100% - 0.8px),
    70.7% calc(100% - 1.8px),
    68.3% calc(100% - 2.0px),
    66.2% calc(100% - 1.1px),
    62.9% calc(100% - 0.7px),
    59.4% calc(100% - 0.7px),
    56.5% calc(100% - 1.0px),
    54.2% calc(100% - 0.3px),
    52.2% calc(100% - 0.7px),
    49.5% calc(100% - 1.0px),
    46.3% calc(100% - 0.7px),
    44.1% calc(100% - 2.0px),
    42.6% calc(100% - 0.9px),
    40.9% calc(100% - 0.8px),
    39.3% calc(100% - 0.5px),
    36.1% calc(100% - 0.4px),
    33.0% calc(100% - 0.5px),
    29.2% calc(100% - 1.8px),
    26.1% calc(100% - 0.7px),
    24.5% calc(100% - 0.3px),
    21.8% calc(100% - 0.5px),
    19.9% calc(100% - 1.1px),
    17.0% calc(100% - 1.1px),
    13.1% calc(100% - 1.9px),
    9.9% calc(100% - 0.5px),
    7.4% calc(100% - 0.5px),
    5.4% calc(100% - 0.8px),
    2.4% calc(100% - 0.6px),
    0.5% calc(100% - 0.4px),
    0.9px 99.0%,
    0.8px 95.7%,
    0.7px 93.3%,
    0.8px 90.4%,
    1.0px 88.2%,
    0.6px 85.1%,
    0.3px 83.6%,
    0.7px 81.7%,
    0.9px 79.9%,
    0.6px 77.4%,
    1.0px 73.8%,
    0.4px 72.4%,
    0.5px 70.3%,
    0.7px 67.6%,
    0.2px 63.7%,
    0.7px 60.5%,
    1.0px 56.6%,
    1.1px 52.8%,
    0.7px 51.0%,
    0.6px 48.0%,
    1.1px 44.9%,
    0.7px 42.8%,
    1.0px 40.0%,
    1.0px 38.0%,
    1.1px 34.9%,
    1.0px 31.7%,
    0.6px 30.3%,
    0.4px 28.7%,
    0.6px 26.6%,
    0.2px 24.1%,
    0.2px 20.3%,
    2.4px 16.5%,
    0.6px 14.6%,
    1.1px 12.8%,
    1.6px 10.9%,
    0.9px 9.3%,
    2.3px 5.4%,
    0.4px 2.1%
  );
  --slip-edge: polygon(
    1.3% 2.0px,
    4.1% 0.8px,
    7.2% 0.2px,
    10.1% 0.3px,
    12.4% 0.7px,
    15.1% 0.4px,
    18.3% 0.9px,
    20.0% 1.0px,
    23.4% 0.8px,
    24.8% 1.1px,
    26.8% 1.9px,
    28.6% 1.9px,
    31.5% 0.5px,
    34.4% 0.7px,
    36.1% 0.4px,
    39.8% 0.9px,
    42.0% 1.0px,
    43.4% 0.6px,
    45.6% 1.0px,
    49.4% 0.9px,
    51.4% 1.7px,
    52.9% 0.7px,
    54.7% 0.5px,
    56.7% 0.5px,
    59.9% 0.6px,
    62.9% 2.1px,
    65.1% 1.1px,
    67.1% 0.5px,
    68.7% 2.4px,
    70.3% 0.6px,
    73.5% 0.8px,
    77.2% 0.9px,
    80.4% 0.2px,
    82.2% 2.0px,
    84.1% 0.5px,
    85.7% 0.9px,
    87.5% 0.3px,
    89.5% 1.0px,
    91.6% 1.7px,
    93.6% 0.9px,
    97.6% 0.2px,
    calc(100% - 1.1px) 0.6%,
    calc(100% - 0.6px) 2.6%,
    calc(100% - 2.0px) 6.5%,
    calc(100% - 0.8px) 8.6%,
    calc(100% - 1.0px) 11.8%,
    calc(100% - 0.5px) 13.6%,
    calc(100% - 1.1px) 15.9%,
    calc(100% - 0.8px) 19.8%,
    calc(100% - 0.8px) 22.8%,
    calc(100% - 0.7px) 26.4%,
    calc(100% - 0.8px) 30.2%,
    calc(100% - 0.4px) 33.3%,
    calc(100% - 0.4px) 36.0%,
    calc(100% - 0.5px) 37.6%,
    calc(100% - 1.0px) 39.9%,
    calc(100% - 0.8px) 41.7%,
    calc(100% - 1.1px) 43.2%,
    calc(100% - 0.8px) 45.4%,
    calc(100% - 0.9px) 48.5%,
    calc(100% - 1.1px) 51.3%,
    calc(100% - 0.7px) 53.0%,
    calc(100% - 1.0px) 56.0%,
    calc(100% - 0.9px) 57.7%,
    calc(100% - 0.6px) 60.7%,
    calc(100% - 0.9px) 63.8%,
    calc(100% - 0.2px) 65.6%,
    calc(100% - 0.9px) 69.5%,
    calc(100% - 0.3px) 72.3%,
    calc(100% - 0.3px) 74.7%,
    calc(100% - 1.0px) 77.0%,
    calc(100% - 2.0px) 78.6%,
    calc(100% - 0.2px) 81.2%,
    calc(100% - 0.8px) 83.2%,
    calc(100% - 0.9px) 86.2%,
    calc(100% - 0.4px) 88.0%,
    calc(100% - 1.7px) 91.3%,
    calc(100% - 1.0px) 93.0%,
    calc(100% - 0.2px) 97.0%,
    98.3% calc(100% - 0.5px),
    95.2% calc(100% - 0.9px),
    93.7% calc(100% - 0.8px),
    91.7% calc(100% - 2.3px),
    89.9% calc(100% - 0.7px),
    87.3% calc(100% - 1.0px),
    84.6% calc(100% - 0.3px),
    81.7% calc(100% - 0.6px),
    78.8% calc(100% - 0.8px),
    75.4% calc(100% - 0.6px),
    72.9% calc(100% - 1.6px),
    70.6% calc(100% - 0.3px),
    68.8% calc(100% - 0.9px),
    67.0% calc(100% - 0.7px),
    63.3% calc(100% - 1.0px),
    59.4% calc(100% - 0.8px),
    56.6% calc(100% - 0.7px),
    54.7% calc(100% - 1.0px),
    52.7% calc(100% - 0.4px),
    51.1% calc(100% - 0.2px),
    47.7% calc(100% - 0.6px),
    45.8% calc(100% - 0.6px),
    43.3% calc(100% - 2.3px),
    41.0% calc(100% - 1.9px),
    39.2% calc(100% - 0.9px),
    37.4% calc(100% - 1.0px),
    36.0% calc(100% - 1.1px),
    32.0% calc(100% - 2.3px),
    28.6% calc(100% - 0.3px),
    24.8% calc(100% - 1.6px),
    22.6% calc(100% - 1.0px),
    21.0% calc(100% - 0.3px),
    19.4% calc(100% - 0.2px),
    16.3% calc(100% - 0.3px),
    12.8% calc(100% - 0.9px),
    11.2% calc(100% - 0.7px),
    9.5% calc(100% - 0.7px),
    7.3% calc(100% - 0.8px),
    3.9% calc(100% - 0.6px),
    1.6% calc(100% - 2.3px),
    0.7px 99.5%,
    2.0px 96.5%,
    1.0px 94.5%,
    0.6px 90.7%,
    0.6px 89.0%,
    1.1px 86.6%,
    1.0px 84.3%,
    0.3px 82.3%,
    0.4px 80.8%,
    1.7px 78.5%,
    0.6px 74.6%,
    2.4px 73.1%,
    2.1px 71.4%,
    1.0px 69.5%,
    0.4px 67.6%,
    0.5px 64.9%,
    0.9px 61.5%,
    0.5px 58.2%,
    0.9px 55.8%,
    0.6px 52.1%,
    0.9px 50.0%,
    0.6px 47.4%,
    0.8px 45.3%,
    0.5px 41.3%,
    0.5px 39.2%,
    0.7px 36.8%,
    0.7px 34.0%,
    0.3px 31.2%,
    0.2px 28.8%,
    0.9px 25.0%,
    0.3px 21.7%,
    1.8px 19.2%,
    0.4px 15.6%,
    1.9px 13.4%,
    0.3px 10.0%,
    0.7px 7.5%,
    0.3px 3.6%,
    0.3px 1.8%,
    0.6px 0.2%
  );
  --paper-edge-b: polygon(
    0.1% 0.5px,
    2.2% 1.0px,
    3.7% 0.8px,
    5.6% 2.5px,
    8.1% 0.3px,
    10.3% 0.8px,
    11.4% 2.6px,
    13.9% 1.4px,
    16.2% 0.4px,
    17.9% 1.8px,
    20.7% 0.8px,
    23.2% 0.8px,
    24.5% 2.1px,
    25.7% 1.9px,
    27.3% 1.5px,
    30.0% 2.1px,
    32.6% 2.4px,
    34.7% 2.2px,
    37.0% 0.8px,
    38.5% 1.5px,
    41.1% 2.5px,
    43.5% 1.8px,
    45.0% 2.4px,
    46.3% 1.2px,
    48.7% 0.7px,
    50.9% 2.4px,
    53.3% 0.3px,
    55.3% 1.5px,
    57.6% 1.1px,
    59.1% 0.4px,
    60.0% 0.8px,
    62.1% 0.5px,
    64.1% 2.5px,
    66.3% 0.7px,
    67.6% 2.0px,
    69.5% 1.0px,
    70.5% 2.2px,
    72.8% 2.2px,
    75.1% 0.4px,
    76.3% 1.8px,
    78.4% 0.8px,
    80.1% 0.9px,
    81.4% 1.6px,
    84.2% 0.4px,
    86.5% 1.4px,
    87.6% 2.5px,
    89.6% 1.9px,
    92.3% 2.1px,
    94.8% 0.7px,
    95.8% 2.1px,
    97.9% 1.7px,
    calc(100% - 1.7px) 0.8%,
    calc(100% - 0.8px) 2.9%,
    calc(100% - 0.8px) 5.2%,
    calc(100% - 2.0px) 7.9%,
    calc(100% - 0.6px) 9.0%,
    calc(100% - 0.7px) 11.7%,
    calc(100% - 0.4px) 13.4%,
    calc(100% - 0.3px) 14.8%,
    calc(100% - 1.6px) 17.3%,
    calc(100% - 1.6px) 18.7%,
    calc(100% - 0.6px) 21.3%,
    calc(100% - 1.5px) 22.6%,
    calc(100% - 1.4px) 23.7%,
    calc(100% - 1.7px) 25.5%,
    calc(100% - 0.3px) 27.3%,
    calc(100% - 1.7px) 28.4%,
    calc(100% - 1.4px) 30.1%,
    calc(100% - 0.6px) 31.9%,
    calc(100% - 2.4px) 34.4%,
    calc(100% - 2.1px) 35.7%,
    calc(100% - 1.1px) 37.7%,
    calc(100% - 1.4px) 39.1%,
    calc(100% - 1.5px) 40.8%,
    calc(100% - 0.6px) 42.1%,
    calc(100% - 2.2px) 43.3%,
    calc(100% - 2.0px) 44.7%,
    calc(100% - 2.1px) 47.1%,
    calc(100% - 1.8px) 48.3%,
    calc(100% - 1.8px) 50.8%,
    calc(100% - 0.6px) 53.5%,
    calc(100% - 0.7px) 55.8%,
    calc(100% - 2.2px) 58.2%,
    calc(100% - 1.5px) 59.7%,
    calc(100% - 1.8px) 61.8%,
    calc(100% - 1.0px) 64.3%,
    calc(100% - 0.5px) 65.3%,
    calc(100% - 1.9px) 67.8%,
    calc(100% - 0.7px) 70.5%,
    calc(100% - 2.3px) 71.7%,
    calc(100% - 0.6px) 73.1%,
    calc(100% - 1.7px) 74.4%,
    calc(100% - 2.4px) 75.3%,
    calc(100% - 2.5px) 76.7%,
    calc(100% - 0.5px) 78.4%,
    calc(100% - 2.3px) 79.7%,
    calc(100% - 0.6px) 81.8%,
    calc(100% - 1.3px) 83.5%,
    calc(100% - 1.2px) 85.1%,
    calc(100% - 1.1px) 87.5%,
    calc(100% - 1.2px) 89.3%,
    calc(100% - 1.4px) 91.8%,
    calc(100% - 2.3px) 93.3%,
    calc(100% - 1.6px) 94.6%,
    calc(100% - 2.2px) 95.8%,
    calc(100% - 2.5px) 97.2%,
    calc(100% - 1.1px) 98.5%,
    calc(100% - 2.5px) 99.4%,
    99.2% calc(100% - 1.7px),
    96.5% calc(100% - 0.8px),
    93.9% calc(100% - 1.2px),
    92.9% calc(100% - 1.2px),
    91.4% calc(100% - 0.4px),
    90.5% calc(100% - 0.7px),
    88.6% calc(100% - 2.1px),
    85.9% calc(100% - 0.7px),
    83.5% calc(100% - 2.5px),
    81.8% calc(100% - 1.4px),
    79.2% calc(100% - 2.1px),
    77.0% calc(100% - 0.8px),
    75.7% calc(100% - 2.1px),
    73.7% calc(100% - 1.6px),
    72.6% calc(100% - 1.4px),
    70.7% calc(100% - 1.5px),
    69.4% calc(100% - 1.1px),
    67.5% calc(100% - 1.6px),
    65.5% calc(100% - 2.3px),
    63.2% calc(100% - 2.3px),
    62.2% calc(100% - 1.8px),
    60.8% calc(100% - 1.0px),
    58.9% calc(100% - 0.3px),
    57.0% calc(100% - 2.1px),
    55.1% calc(100% - 0.8px),
    53.0% calc(100% - 1.3px),
    52.1% calc(100% - 1.0px),
    50.4% calc(100% - 0.5px),
    48.6% calc(100% - 0.9px),
    47.5% calc(100% - 2.5px),
    45.1% calc(100% - 0.6px),
    43.2% calc(100% - 2.2px),
    42.1% calc(100% - 1.5px),
    40.1% calc(100% - 0.9px),
    37.5% calc(100% - 1.0px),
    36.1% calc(100% - 0.5px),
    34.8% calc(100% - 2.3px),
    32.8% calc(100% - 1.5px),
    31.2% calc(100% - 2.4px),
    29.1% calc(100% - 2.0px),
    27.1% calc(100% - 1.0px),
    26.2% calc(100% - 1.5px),
    25.2% calc(100% - 1.3px),
    22.9% calc(100% - 0.6px),
    21.6% calc(100% - 1.7px),
    20.6% calc(100% - 2.0px),
    19.1% calc(100% - 1.9px),
    17.6% calc(100% - 0.7px),
    15.4% calc(100% - 1.0px),
    14.0% calc(100% - 2.4px),
    12.9% calc(100% - 0.9px),
    10.7% calc(100% - 2.6px),
    8.7% calc(100% - 0.5px),
    6.0% calc(100% - 0.5px),
    4.2% calc(100% - 1.3px),
    2.5% calc(100% - 0.7px),
    1.0% calc(100% - 2.6px),
    2.5px 99.2%,
    0.6px 96.4%,
    1.9px 94.9%,
    1.0px 92.5%,
    2.1px 90.8%,
    0.8px 89.2%,
    1.9px 87.8%,
    2.3px 85.7%,
    0.7px 83.9%,
    0.9px 82.2%,
    1.4px 80.1%,
    2.1px 78.2%,
    0.7px 75.9%,
    1.2px 73.7%,
    1.7px 71.1%,
    0.9px 69.1%,
    1.0px 67.0%,
    2.2px 65.0%,
    2.4px 62.8%,
    0.4px 61.0%,
    0.4px 59.5%,
    1.2px 58.3%,
    0.6px 56.3%,
    2.2px 53.7%,
    0.9px 51.9%,
    2.2px 50.3%,
    2.4px 48.6%,
    2.1px 47.6%,
    0.9px 46.4%,
    1.2px 44.9%,
    2.5px 43.0%,
    2.6px 41.1%,
    0.4px 39.5%,
    2.5px 37.2%,
    2.4px 35.3%,
    2.4px 33.2%,
    1.5px 30.5%,
    0.6px 27.8%,
    1.5px 26.6%,
    0.8px 24.5%,
    1.8px 22.8%,
    2.5px 20.2%,
    2.2px 18.8%,
    1.6px 16.9%,
    2.4px 15.8%,
    2.0px 14.4%,
    1.9px 11.9%,
    2.5px 10.2%,
    0.9px 8.0%,
    0.3px 5.5%,
    1.4px 4.1%,
    2.3px 3.0%,
    0.9px 1.7%
  );
  --slip-edge: polygon(
    0.8% 0.5px,
    2.6% 1.2px,
    4.4% 1.4px,
    6.6% 1.3px,
    7.5% 1.2px,
    8.7% 0.5px,
    10.2% 0.7px,
    12.2% 1.1px,
    14.6% 0.8px,
    16.8% 1.4px,
    19.2% 0.6px,
    21.2% 1.7px,
    23.6% 1.4px,
    25.8% 0.4px,
    28.2% 1.9px,
    29.5% 0.4px,
    31.1% 0.6px,
    32.0% 0.9px,
    34.1% 0.7px,
    35.6% 1.3px,
    37.7% 1.2px,
    38.8% 0.8px,
    40.1% 1.7px,
    41.7% 1.5px,
    43.1% 0.9px,
    45.6% 0.4px,
    47.8% 1.1px,
    49.2% 1.2px,
    51.8% 1.8px,
    53.5% 1.6px,
    54.8% 0.5px,
    56.1% 0.5px,
    58.3% 1.3px,
    59.5% 1.8px,
    60.9% 0.8px,
    63.6% 0.9px,
    65.9% 1.2px,
    67.6% 1.3px,
    68.5% 1.3px,
    70.0% 0.9px,
    72.7% 0.7px,
    75.4% 0.9px,
    76.5% 0.5px,
    79.2% 0.5px,
    80.8% 1.1px,
    83.1% 0.9px,
    85.2% 1.7px,
    86.4% 1.6px,
    88.6% 1.6px,
    89.5% 0.6px,
    90.6% 1.1px,
    91.8% 1.6px,
    93.3% 0.5px,
    95.1% 1.5px,
    96.3% 1.6px,
    97.3% 0.7px,
    99.5% 1.7px,
    calc(100% - 0.6px) 0.1%,
    calc(100% - 1.7px) 1.4%,
    calc(100% - 1.9px) 3.7%,
    calc(100% - 0.4px) 4.9%,
    calc(100% - 0.8px) 7.4%,
    calc(100% - 1.9px) 9.7%,
    calc(100% - 0.9px) 11.0%,
    calc(100% - 1.8px) 12.8%,
    calc(100% - 1.2px) 13.8%,
    calc(100% - 0.7px) 15.3%,
    calc(100% - 1.5px) 17.3%,
    calc(100% - 1.8px) 19.0%,
    calc(100% - 1.4px) 20.2%,
    calc(100% - 0.9px) 21.8%,
    calc(100% - 1.9px) 23.0%,
    calc(100% - 1.1px) 25.7%,
    calc(100% - 1.3px) 27.9%,
    calc(100% - 1.5px) 29.7%,
    calc(100% - 0.7px) 32.2%,
    calc(100% - 1.8px) 34.1%,
    calc(100% - 1.4px) 36.1%,
    calc(100% - 0.6px) 38.3%,
    calc(100% - 1.2px) 39.7%,
    calc(100% - 0.7px) 41.8%,
    calc(100% - 0.8px) 42.9%,
    calc(100% - 0.9px) 44.4%,
    calc(100% - 1.7px) 46.4%,
    calc(100% - 1.2px) 47.7%,
    calc(100% - 0.4px) 49.7%,
    calc(100% - 1.8px) 52.5%,
    calc(100% - 0.6px) 54.1%,
    calc(100% - 1.4px) 56.3%,
    calc(100% - 1.6px) 57.4%,
    calc(100% - 1.7px) 59.3%,
    calc(100% - 0.5px) 62.1%,
    calc(100% - 1.2px) 63.6%,
    calc(100% - 0.7px) 65.6%,
    calc(100% - 0.6px) 68.3%,
    calc(100% - 1.6px) 70.1%,
    calc(100% - 1.4px) 72.2%,
    calc(100% - 1.4px) 73.9%,
    calc(100% - 1.6px) 76.2%,
    calc(100% - 0.7px) 77.4%,
    calc(100% - 1.8px) 78.4%,
    calc(100% - 1.6px) 80.6%,
    calc(100% - 1.8px) 82.5%,
    calc(100% - 0.9px) 83.7%,
    calc(100% - 0.5px) 85.7%,
    calc(100% - 1.1px) 87.2%,
    calc(100% - 0.5px) 89.8%,
    calc(100% - 1.1px) 90.8%,
    calc(100% - 1.6px) 92.6%,
    calc(100% - 0.7px) 93.6%,
    calc(100% - 1.5px) 95.8%,
    calc(100% - 1.4px) 97.9%,
    99.8% calc(100% - 1.5px),
    98.5% calc(100% - 1.5px),
    97.5% calc(100% - 0.6px),
    96.4% calc(100% - 1.3px),
    93.7% calc(100% - 1.9px),
    91.4% calc(100% - 0.5px),
    89.2% calc(100% - 1.7px),
    87.4% calc(100% - 1.0px),
    85.2% calc(100% - 1.1px),
    82.8% calc(100% - 0.4px),
    80.1% calc(100% - 1.4px),
    78.7% calc(100% - 0.5px),
    76.0% calc(100% - 0.7px),
    73.7% calc(100% - 1.2px),
    71.9% calc(100% - 1.3px),
    69.3% calc(100% - 1.2px),
    67.7% calc(100% - 0.6px),
    65.7% calc(100% - 1.7px),
    64.0% calc(100% - 1.3px),
    61.6% calc(100% - 1.5px),
    59.2% calc(100% - 1.7px),
    57.6% calc(100% - 1.1px),
    56.5% calc(100% - 0.4px),
    55.0% calc(100% - 1.3px),
    54.0% calc(100% - 0.7px),
    52.8% calc(100% - 1.6px),
    51.6% calc(100% - 0.8px),
    49.6% calc(100% - 1.7px),
    48.2% calc(100% - 1.8px),
    45.5% calc(100% - 1.6px),
    43.4% calc(100% - 1.2px),
    41.9% calc(100% - 1.2px),
    40.7% calc(100% - 1.5px),
    38.1% calc(100% - 0.8px),
    35.7% calc(100% - 0.7px),
    34.6% calc(100% - 1.0px),
    33.7% calc(100% - 1.5px),
    32.2% calc(100% - 1.0px),
    31.0% calc(100% - 1.2px),
    29.3% calc(100% - 1.0px),
    28.2% calc(100% - 1.6px),
    26.6% calc(100% - 0.4px),
    24.9% calc(100% - 0.7px),
    23.6% calc(100% - 1.6px),
    22.5% calc(100% - 0.7px),
    19.9% calc(100% - 0.4px),
    18.6% calc(100% - 1.8px),
    15.8% calc(100% - 0.6px),
    13.1% calc(100% - 1.6px),
    10.5% calc(100% - 0.5px),
    7.8% calc(100% - 0.6px),
    6.9% calc(100% - 0.8px),
    5.2% calc(100% - 1.8px),
    4.1% calc(100% - 1.0px),
    3.0% calc(100% - 0.5px),
    0.9% calc(100% - 0.4px),
    0.5px 99.2%,
    0.7px 96.7%,
    0.5px 94.3%,
    1.2px 92.2%,
    1.4px 91.1%,
    0.9px 89.2%,
    1.4px 87.7%,
    1.5px 85.4%,
    0.9px 83.5%,
    1.8px 82.5%,
    0.8px 81.1%,
    1.2px 79.0%,
    0.5px 76.9%,
    0.8px 75.2%,
    1.7px 73.2%,
    1.6px 70.6%,
    0.5px 68.9%,
    1.1px 66.8%,
    0.8px 65.1%,
    0.9px 62.4%,
    1.7px 60.0%,
    0.9px 58.7%,
    0.5px 57.5%,
    0.7px 56.0%,
    0.6px 54.4%,
    1.8px 53.3%,
    1.0px 50.7%,
    0.4px 49.7%,
    0.5px 47.0%,
    1.4px 46.0%,
    0.8px 44.7%,
    0.7px 42.1%,
    0.8px 40.2%,
    1.4px 38.4%,
    1.6px 36.9%,
    1.6px 34.8%,
    1.5px 32.5%,
    1.0px 31.1%,
    1.5px 29.8%,
    1.4px 27.3%,
    0.8px 25.5%,
    1.5px 23.9%,
    1.4px 22.1%,
    0.8px 20.3%,
    1.4px 17.9%,
    1.2px 15.2%,
    0.9px 13.7%,
    0.9px 11.0%,
    1.4px 9.5%,
    1.2px 7.5%,
    1.3px 5.7%,
    0.9px 3.8%,
    0.9px 2.7%,
    0.5px 0.9%
  );

  /* type — old-style editorial serif everywhere on the paper;
     stencil-mono caps for dates and wayfinding; stencil face for
     anything painted on the wall itself */
  --font-display: "Newsreader", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --font-body: "Newsreader", Charter, "Iowan Old Style", Georgia, serif;
  --font-stencil: "Allerta Stencil", "Arial Black", sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

/* ---------------------------------------------------------------- base */

/* Newsreader variable (weight 200-800, optical size 6-72): the display
   masthead and the text face are the same family at different optical
   sizes — the browser picks opsz from font-size automatically. */
@font-face {
  font-family: "Newsreader";
  src: url("/assets/newsreader.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Newsreader";
  src: url("/assets/newsreader-italic.woff2") format("woff2");
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "Allerta Stencil";
  src: url("/assets/allerta-stencil.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; }

/* the canvas beyond any layout box (overscroll, zoom) is always the wall */
html { -webkit-text-size-adjust: 100%; background: var(--wall-paint); }

body {
  margin: 0;
  /* tape corners intentionally hang past the sheet; never let them widen
     the page (16px doc overflow at 390px without this) */
  overflow-x: hidden;
  overflow-x: clip;
  font-family: var(--font-body);
  font-optical-sizing: auto;
  color: var(--ink);
  background: var(--wall-paint);
}

img { max-width: 100%; height: auto; display: block; }

a { color: inherit; }

:focus-visible {
  outline: 2px dashed currentColor;
  outline-offset: 3px;
}

/* small uppercase mono label — dates, wayfinding printed on the paper */
.kind, .paper-line {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* aged translucent tape at the sheet's top corners — a real extracted
   asset (assets/tape-*.webp, see scripts/texture/extract-tape.mjs),
   never a CSS-vector fake. It straddles paper and wall; the shared
   light+grain pass runs over it like everything else. */
.tape {
  position: absolute;
  z-index: 3;
  width: clamp(74px, 7.5vw, 106px);
  height: auto;
  pointer-events: none;
  opacity: 0.85;
  /* the hair of shadow tape itself casts — not a floating-card shadow */
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.14));
}

.tape-l { top: -13px; left: -24px; transform: rotate(-38deg); }
.tape-r { top: -13px; right: -24px; transform: rotate(38deg); }

@media print {
  .sheet-foot { display: none; }
  body { background: #fff; }
}

/* ---------------------------------------------------------------- wall
   The whole site is ONE bill: a single wheat-pasted notice carrying the
   full index, posted on a painted plywood fence where bills are forbidden.
   Composition per the north star (reference/northstar/home-desktop.png):
   the bill takes ~40% of the frame, BETWEEN two POST NO BILLS stencils
   that are partially cropped by the viewport edges. The hoarding was
   painted once and weathered together — uniform paint, quiet grain. */

.wall {
  position: relative;
  min-height: 100svh;
  overflow: hidden;
  isolation: isolate;
  background: var(--wall-paint);
  padding: clamp(2.2rem, 6vh, 4.2rem) 1rem clamp(3rem, 8vh, 5.5rem);
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------- boards */

.boards {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  view-transition-name: wall;
}

/* Each board is its own plank crop of the SAME paint job — one color,
   one sheen, only the grain offset differs. The texture is the baked
   green composite; the flat paint color beneath is only a loading
   fallback, so nothing here depends on a blend mode. */
.board {
  position: relative;
  flex: 0 0 clamp(380px, 34vw, 560px);
  background-color: var(--wall-paint);
  background-image: var(--tex-wall);
  background-position: var(--gx) var(--gy);
  background-size: 1050px;
}

/* board seam: dark gap plus a lit edge on the next board */
.board + .board {
  border-left: 2px solid var(--seam-gap);
  box-shadow: inset 2px 0 0 var(--seam-lit);
}

/* ----------------------------------------------------------- stencils
   Two stencils in the periphery, partially cropped by the frame edges.
   The bill never touches the letters. On narrow screens they leave the
   frame entirely (proportion honesty — see JUDGING.md axis 5). */

.wall .stencil {
  position: absolute;
  z-index: 1;
  top: clamp(120px, 22vh, 220px);
  width: clamp(300px, 26vw, 430px);
  aspect-ratio: 1;
  opacity: var(--so, 0.85);
  transform: rotate(var(--srot, 0deg));
}

/* Two passes through the same letter mask (stencil-mask.webp: paint
   density = alpha × mottle, so the green shows through thin spots).
   ::before is the overspray cloud — the same letters blurred wide and
   faint, the way spray drifts past the cut edge. ::after is the paint
   itself: wall relief tinted overspray white, so brush grooves read
   inside the letters. No glow filters anywhere. */
.wall .stencil::before,
.wall .stencil::after {
  content: "";
  position: absolute;
  inset: 0;
  mask-image: url("/assets/stencil-mask.webp");
  mask-size: 100% 100%;
}

.wall .stencil::before {
  background: #dfe4da;
  filter: blur(6px);
  opacity: 0.3;
  scale: 1.01;
}

.wall .stencil::after {
  background-image: url("/assets/stencil-paint.webp");
  background-position: var(--spx, 0) var(--spy, 0);
  background-size: 1050px;
  /* no blur here: blurring a masked layer bleeds a dark rim around the
     letter edges (measured ~15-20 luminance below wall baseline); the
     mask's own soft alpha already carries the spray edge */
}

.stencil-left { left: 0; translate: -12% 0; }
.stencil-right { right: 0; translate: 30% 2.5vh; }

/* The crew's own small marks: the panel number sprayed low on the first
   board — the site reads it as the running count of bills ever posted.
   Same paint-through-relief treatment as the stencils, much fainter. */
.panel-no {
  position: absolute;
  bottom: clamp(1.2rem, 5vh, 3rem);
  left: 9%;
  font-family: var(--font-stencil);
  font-size: 1.5rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background-image: url("/assets/stencil-paint.webp");
  background-size: 420px;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  opacity: 0.42;
  transform: rotate(var(--mrot, 0deg));
}

/* The ghosts of bills that moved on: faint paste-residue scars in the
   periphery (extracted asset, heavily attenuated). History, not clutter —
   two at most, never near the letters or the notice. */
.paste-scar {
  position: absolute;
  z-index: 0;
  width: clamp(170px, 15vw, 250px);
  aspect-ratio: 1;
  background: var(--tex-paste-scar) center / contain no-repeat;
  opacity: var(--sco, 0.14);
  transform: rotate(var(--scr, 0deg));
}

.paste-scar-a { left: 5%; bottom: 8%; }
.paste-scar-b { right: 2%; top: 6%; }

@media (max-width: 1023px) {
  .wall .stencil, .paste-scar, .panel-no { display: none; }
}

/* ------------------------------------------------------------- notice */

.notice {
  position: relative;
  z-index: 2;
  width: min(620px, 92vw);
  /* a posted sheet is portrait even when the index is young */
  min-height: min(80vh, 820px);
  margin: clamp(1.6rem, 7vh, 4.5rem) auto 0;
  /* the bottom of the sheet is the tear-off fringe: the main paper stops
     above it and each tab carries its own piece (matter.css) */
  --fringe: 5.1rem;
  padding: clamp(1.9rem, 5vw, 2.9rem) clamp(1.3rem, 4.5vw, 2.7rem) 0;
  view-transition-name: sheet;
}

/* The paper itself lives on a pseudo-element so its silhouette can be
   cut a hair off-true (--paper-edge) without clipping the tape that
   straddles onto the wall. Wheat-pasted skin, not a card: NO drop
   shadow — separation comes from paste soak at the edges, a whisper of
   buckle, and the wall's grain baked faintly into the paper stock. */
.notice::before {
  content: "";
  position: absolute;
  inset: 0 0 var(--fringe, 0) 0;
  z-index: -1;
  background-color: var(--paper);
  background-image: var(--tex-paper);
  background-size: 900px;
  clip-path: var(--paper-edge);
  box-shadow:
    inset 0 0 58px var(--paste-soak),
    inset 0 0 5px var(--paste-soak),
    inset 0 0 2px rgba(96, 80, 50, 0.38),
    inset 0 -42px 72px -26px var(--paste-soak),
    inset 0 14px 26px -18px rgba(255, 255, 255, 0.28),
    inset 0 -16px 30px -20px rgba(0, 0, 0, 0.18);
}

/* Dried paste slopped past the sheet when it went up (2026-07-08
   exploration round, macro-paste): a whisper of brush-swipe halo around
   the silhouette, behind the paper, riding the wall. The extracted ring
   stretches along each edge via border-image. */
.notice::after {
  content: "";
  position: absolute;
  inset: -8px -8px calc(var(--fringe, 0px) - 8px);
  z-index: -2;
  border: 30px solid transparent;
  border-image-source: var(--tex-paste-halo);
  border-image-slice: 15.3% 11.7%;
  border-image-repeat: round;
  opacity: 0.55;
}

/* -------------------------------------------------------------- index
   The bill's ledger (2026-07-08 exploration round): title, a catchword
   dot leader, the date at the right margin — the way a timetable page
   carries entries. A thick-thin double rule opens the ledger. */

.index {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 2.5px solid var(--rule);
  position: relative;
}

.index::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 0;
  right: 0;
  border-top: 1px solid var(--rule);
}

.index li { border-bottom: 1px solid var(--rule); }

/* letterspaced year heads appear once the archive spans years */
.index .index-year {
  padding: 0.7em 0 0.55em;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  color: var(--ink-soft);
}

.index a {
  display: block;
  padding: 1rem 0 1.1rem;
  text-decoration: none;
}

.entry-line {
  display: flex;
  /* bottom-aligned so a wrapped title carries the leader and date on its
     LAST line, the way a ledger continuation behaves; if the last line
     is full they wrap to their own dotted continuation line */
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 0 0.5em;
  line-height: 1.35;
}

.index time {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--ink-soft);
  white-space: nowrap;
  /* optically sit the small mono date on the serif baseline */
  margin-bottom: 0.22em;
}

/* leader + date travel as one unit: beside the title's last line when
   it fits, a full dotted continuation line when it doesn't */
.entry-ref {
  flex: 1 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 0.5em;
  min-width: 10em;
}

/* the catchword leader: round dots running title -> date */
.leader {
  flex: 1 0 2.2em;
  height: 1em;
  margin-bottom: 0.32em;
  background-image: radial-gradient(circle, var(--ink-faint) 1px, transparent 1.4px);
  background-size: 7px 3px;
  background-position: left bottom;
  background-repeat: repeat-x;
  opacity: 0.75;
}

.entry-title {
  font-family: var(--font-display);
  font-weight: 650;
  font-size: 1.22rem;
  letter-spacing: 0.002em;
  color: var(--ink);
}

.index a:hover .entry-title,
.index a:focus-visible .entry-title {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--ink-soft);
}

.entry-dek {
  display: block;
  margin-top: 0.28rem;
  font-family: var(--font-body);
  font-size: 0.94rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* ------------------------------------------------ shared light + grain
   One lighting pass and one grain pass over EVERYTHING — boards,
   stencils, paper. This is what makes the sheet belong to the wall.
   Per the north star: one soft daylight, upper left, nearly no
   vignette. */

.wall-light {
  position: absolute;
  inset: 0;
  z-index: 400;
  pointer-events: none;
  background:
    linear-gradient(155deg, rgba(255, 255, 255, 0.07), transparent 52%),
    linear-gradient(335deg, rgba(0, 0, 0, 0.06), transparent 55%),
    radial-gradient(165% 130% at 50% 30%, transparent 62%, var(--wall-vignette));
}

.wall-light::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--tex-wall);
  background-size: 780px;
  mix-blend-mode: soft-light;
  opacity: 0.2;
}

/* on phones the same scene narrows to the sheet itself: paper takes the
   screen over a slim green border, deeper at the top, and the sheet
   runs past the bottom edge — never a vertically centered card */
@media (max-width: 1023px) {
  .wall {
    display: flex;
    flex-direction: column;
    padding: clamp(1.6rem, 5vh, 2.6rem) 0.9rem 0;
  }
  .notice {
    flex: 1 0 auto;
    margin-top: clamp(0.6rem, 3vh, 1.6rem);
    margin-bottom: 0;
    min-height: 100svh;
  }
}

/* ---------------------------------------------------------------- sheet
   Reading distance (north star post-desktop/post-mobile): the sheet takes
   most of the frame with green slivers at the margins; NO stencil, no
   painted wall text at this proximity. Wayfinding is printed ON the
   paper: ← BACK top-left, date top-right, stencil-mono. The paper is
   nearly quiet so the words win. */

.post-page { background-color: var(--wall-paint); }

.up-close {
  position: relative;
  min-height: 100svh;
  isolation: isolate;
  /* wall shows below the sheet's soaked bottom edge at scroll end —
     the paper ends, the wall doesn't (same paste cue as home) */
  padding: clamp(1.4rem, 3.5vw, 2.6rem) clamp(0.7rem, 4vw, 3.4rem) clamp(2.6rem, 7vh, 4.6rem);
}

/* the wall behind the sheet — same paint job as home, seen closer */
.post-boards {
  position: absolute;
  inset: 0;
  z-index: 0;
  view-transition-name: wall;
  background-color: var(--wall-paint);
  /* daylight sheen only — NO vignette here: this element spans the whole
     document, so a radial vignette turns the wall strip below a long
     post's sheet near-black, which reads as a cast shadow and breaks
     the one-daylight rule */
  background-image:
    linear-gradient(155deg, rgba(255, 255, 255, 0.04), transparent 45%),
    var(--tex-wall);
  background-size: auto, 1400px;
}

.sheet {
  position: relative;
  z-index: 1;
  width: min(1120px, 100%);
  margin: 0 auto;
  padding: clamp(1.1rem, 2.6vw, 2rem) clamp(1.25rem, 11vw, 10rem) clamp(2rem, 5vw, 3.4rem);
  view-transition-name: sheet;
}

/* paper on a pseudo-element, silhouette cut a hair off-true — see the
   .notice::before note in wall.css. Pasted skin: NO drop shadow —
   soaked edges + whisper of buckle, heavier where paste pools. */
.sheet::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--paper);
  background-image: var(--tex-paper);
  background-position: var(--tex-x, 0) var(--tex-y, 0);
  background-size: 900px;
  clip-path: var(--paper-edge-b);
  box-shadow:
    inset 0 0 56px var(--paste-soak),
    inset 0 0 5px var(--paste-soak),
    inset 0 0 2px rgba(96, 80, 50, 0.38),
    inset 0 -42px 72px -26px var(--paste-soak),
    inset 0 14px 26px -18px rgba(255, 255, 255, 0.28),
    inset 0 -16px 30px -20px rgba(0, 0, 0, 0.16);
}

/* the same dried-paste slop that rings the home notice, quieter at
   reading distance (see .notice::after in wall.css) */
.sheet::after {
  content: "";
  position: absolute;
  inset: -8px;
  z-index: -2;
  border: 26px solid transparent;
  border-image-source: var(--tex-paste-halo);
  border-image-slice: 15.3% 11.7%;
  border-image-repeat: round;
  opacity: 0.4;
}

/* the same single daylight + grain pass the wall page uses, laid over
   boards AND sheet alike — the sheet belongs to the wall (doctrine #5) */
.up-close .wall-light {
  position: absolute;
  inset: 0;
  z-index: 400;
  pointer-events: none;
  background: linear-gradient(155deg, rgba(255, 255, 255, 0.04), transparent 45%);
}

.up-close .wall-light::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--tex-wall);
  background-size: 1400px;
  mix-blend-mode: soft-light;
  opacity: 0.13;
}

/* --------------------------------------------------------------- head
   One quiet line printed on the paper: back on the left, the honest
   posted date on the right. Then the masthead. */

.paper-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  margin: 0 0 clamp(1.6rem, 4vw, 2.6rem);
  color: var(--ink-soft);
}

.paper-line a {
  text-decoration: none;
  color: var(--ink-soft);
  /* the ONLY way back is this small line — give the tap a real target
     without shifting the print (padding and margin cancel) */
  padding: 0.9em;
  margin: -0.9em;
}
.paper-line a:hover, .paper-line a:focus-visible { color: var(--ink); }

/* The posted date is a rubber stamp (2026-07-08 exploration round,
   city-notice): faded brick ink, a hair off-true, broken by an SVG
   turbulence mask the way a real stamp only half-takes on rough paper.
   Multiply settles the ink into the stock; if a browser drops the blend
   the stamp is merely a little brighter — nothing load-bearing. */
.paper-line .stamp {
  color: var(--stamp-ink);
  border: 2px solid var(--stamp-ink);
  border-radius: 3px;
  padding: 0.32em 0.55em 0.28em;
  transform: rotate(-2.2deg);
  opacity: 0.82;
  mix-blend-mode: multiply;
  mask-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.5' numOctaves='3' seed='11'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0.9 0.9 0.9 0 -0.55'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)'/%3E%3C/svg%3E");
  mask-size: 220px;
  mask-repeat: repeat;
}

/* masthead per the north star: title, hairline rule directly beneath,
   then the dek as the lede below the rule */
.sheet-head h1 {
  margin: 0;
  padding-bottom: clamp(0.9rem, 2.4vw, 1.5rem);
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-display);
  font-weight: 660;
  letter-spacing: -0.005em;
  line-height: 1.04;
  font-size: clamp(2.35rem, 5.6vw, 4rem);
  color: var(--ink);
  text-wrap: balance;
  view-transition-name: post-title;
}

.sheet-head {
  margin-bottom: clamp(1.4rem, 3.2vw, 2rem);
}

.sheet-head .dek {
  max-width: 44rem;
  margin: clamp(1.2rem, 3vw, 1.7rem) 0 0;
  font-size: 1.14rem;
  line-height: 1.6;
  color: var(--ink);
}

/* -------------------------------------------------------------- prose */

.prose {
  max-width: 44rem;
  font-size: 1.0625rem;
  line-height: 1.7;
}

.prose > * { margin-block: 0; }
.prose > * + * { margin-top: 1.15em; }

.prose h2 {
  margin-top: 2em;
  font-family: var(--font-display);
  font-weight: 650;
  letter-spacing: 0;
  line-height: 1.15;
  font-size: 1.45rem;
}

.prose h3 { font-family: var(--font-display); font-weight: 650; font-size: 1.15rem; margin-top: 1.8em; }

.prose a {
  color: var(--mark);
  text-decoration: underline;
  text-decoration-color: var(--mark-soft);
  text-underline-offset: 3px;
}
.prose a:hover { text-decoration-color: var(--mark); }

/* pull quote per the north star: indented italic serif, full ink,
   spoken quotes — not a marker stroke */
.prose blockquote {
  margin: 1.7em 0 1.7em 2.4em;
  padding: 0;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: 1.3em;
  line-height: 1.45;
  color: var(--ink);
}
.prose blockquote p { margin: 0.4em 0; }
.prose blockquote p:first-child::before { content: "\201C"; }
.prose blockquote p:last-child::after { content: "\201D"; }

.prose code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: rgba(0, 0, 0, 0.055);
  padding: 0.1em 0.35em;
  border-radius: 2px;
}

/* Long lines scroll INSIDE the block; scroll shadows (covers ride the
   content, shadows stick to the box) say "there's more" — otherwise a
   cut-off line reads as broken, not scrollable. Solid stock, since the
   covers must be able to hide the shadows completely. */
.prose pre {
  --pre-bg: #e3dbc9;
  overflow-x: auto;
  padding: 1em 1.2em;
  border: 1px solid rgba(0, 0, 0, 0.08);
  background:
    linear-gradient(90deg, var(--pre-bg) 45%, rgba(227, 219, 201, 0)) left center / 36px 100% no-repeat,
    linear-gradient(270deg, var(--pre-bg) 45%, rgba(227, 219, 201, 0)) right center / 36px 100% no-repeat,
    radial-gradient(farthest-side at 0 50%, rgba(38, 34, 27, 0.3), transparent) left center / 16px 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%, rgba(38, 34, 27, 0.3), transparent) right center / 16px 100% no-repeat,
    var(--pre-bg);
  background-attachment: local, local, scroll, scroll, local;
}
.prose pre code { background: none; padding: 0; }

/* field notes: a separate slip of rougher stock pasted onto the bill —
   real paper texture at its own crop, its own soak, a hair off-square */
.prose .field-note {
  margin: 1.9em 0;
  padding: 1.1em 1.3em 1.2em;
  background-color: var(--paper-deep);
  background-image: var(--tex-paper-deep);
  background-position: 310px 140px;
  background-size: 620px;
  transform: rotate(-0.4deg);
  /* a cut slip, not a callout card: deckle edge, soak kept light so the
     border zone doesn't read as a shadow ring. Paper ON paper does cast
     a hair of shadow (unlike paper on paste) — drop-shadow follows the
     clipped silhouette */
  clip-path: var(--slip-edge);
  filter: drop-shadow(0 1px 1px rgba(38, 34, 27, 0.16));
  box-shadow:
    inset 0 0 14px var(--paste-soak),
    inset 0 0 2px var(--paste-soak);
  font-size: 0.95em;
}

.field-note-label {
  margin: 0 0 0.6em;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.prose .field-note p:not(.field-note-label) { margin: 0.4em 0 0; }

/* section break: a printer's ornament row, not a web divider */
.prose hr {
  border: 0;
  height: auto;
  margin: 2.5em auto;
  background: none;
  text-align: center;
}

.prose hr::before {
  content: "\2726\2003\2726\2003\2726";
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 0;
  color: var(--ink-faint);
  opacity: 0.85;
}

.prose img { margin: 1.8em auto; }

/* --------------------------------------------------------------- foot
   The sheet signs off in its own voice, then points along the wall. */

.fin {
  margin: 3rem 0 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.3em;
  color: var(--ink-soft);
}

.fin-meta {
  margin: 0.7rem 0 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.sheet-foot {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.4rem;
  align-items: start;
  margin-top: 2.4rem;
  padding-top: 1.3rem;
  border-top: 1px solid var(--rule);
}

.sheet-foot a {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.98rem;
  line-height: 1.4;
  color: var(--ink);
  text-decoration: none;
}
.sheet-foot a:hover { text-decoration: underline; text-underline-offset: 3px; }

.sheet-foot small {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.3em;
}

/* the pointing hand a printed page would use for "that way" */
.sheet-foot .manicule {
  font-family: var(--font-display);
  font-size: 1.5em;
  line-height: 0;
  vertical-align: -0.12em;
  letter-spacing: 0;
}

.foot-older { text-align: right; }
/* a lone neighbor keeps the full measure instead of half an empty grid */
.sheet-foot a:only-child { grid-column: 1 / -1; }

/* -------------------------------------------------------------- mobile
   Nearly full-bleed sheet, hairline green slivers, the head compact so
   the title block starts within the top ~15% of the viewport. */

@media (max-width: 700px) {
  .up-close { padding: 1.1rem 0.55rem 0; }
  .sheet { padding: 0.95rem 1.35rem 2rem; }
  .paper-line { margin-bottom: 1.1rem; }
  .prose { font-size: 1rem; }
}

/* --------------------------------------------------------------- 404
   A modest notice posted where the bill was torn down — not a full
   sheet, just enough paper to say so. */

.notfound .sheet {
  width: min(560px, 92vw);
  min-height: 0;
  margin-top: clamp(2rem, 10vh, 6rem);
  padding: clamp(1.4rem, 3vw, 1.9rem) clamp(1.4rem, 4vw, 2.4rem) clamp(1.8rem, 4vw, 2.6rem);
}
.notfound h1 { font-family: var(--font-display); font-weight: 660; margin: 0.4rem 0; }
.notfound .kind { color: var(--mark); }
.notfound a { color: var(--mark); }

/* --------------------------------------------------------------- matter
   Publishing affordances: footnotes, image plates, tables, the wall's
   small print. Everything here prints as ink on the same sheet — no web
   widget chrome. Loads after sheet.css so it can retune prose defaults
   (figure/img spacing) and before motion.css. */

/* ------------------------------------------------------------ footnotes
   The bill's own small print at its foot: a numbered superscript in the
   body, an ordered list of notes after "— FIN —", each with a return
   arrow back to where it was called. */

.fn-ref {
  font-size: 0.7em;
  line-height: 0;
  vertical-align: super;
}

.fn-ref a {
  color: var(--mark);
  text-decoration: none;
  padding: 0 0.05em;
}

.fn-ref a:hover, .fn-ref a:focus-visible {
  text-decoration: underline;
  text-decoration-color: var(--mark-soft);
}

.notes {
  margin-top: 2.4rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
}

.notes-label {
  margin: 0 0 0.9em;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.notes-list {
  margin: 0;
  padding-left: 1.3em;
  font-family: var(--font-body);
  font-size: 0.88em;
  line-height: 1.6;
  color: var(--ink-soft);
}

.notes-list li + li { margin-top: 0.55em; }
.notes-list li > p { margin: 0; }
.notes-list li > p + p { margin-top: 0.5em; }

.notes-list li:target { color: var(--ink); }

.fn-back {
  margin-left: 0.15em;
  color: var(--ink-faint);
  text-decoration: none;
  font-size: 0.92em;
  /* adjacent return arrows (multi-reference notes) need separable taps */
  padding: 0.5em 0.35em;
  margin-block: -0.5em;
}

.fn-back:hover, .fn-back:focus-visible { color: var(--mark); }

/* ---------------------------------------------------------------- plate
   A standalone image paragraph reads as a printed plate pasted into the
   column: it fills the measure, a hairline border stands in for a
   halftone edge, and the caption is set as small print, flush left. */

.prose figure {
  margin: 1.8em 0;
}

.prose figure img {
  display: block;
  width: 100%;
  height: auto;
  margin: 0;
  border: 1px solid var(--rule);
}

.prose figcaption {
  margin-top: 0.6em;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-align: left;
}

/* ---------------------------------------------------------------- table
   Hairlines only — top, header underline, bottom. No zebra, no vertical
   rules; this is a typeset table, not a spreadsheet. */

.prose table {
  display: block;
  overflow-x: auto;
  width: 100%;
  margin: 1.8em 0;
  border-top: 1px solid var(--rule);
  border-collapse: collapse;
  font-size: 0.92em;
}

.prose th, .prose td {
  padding: 0.55em 1.3em 0.55em 0;
  text-align: left;
  vertical-align: top;
}

.prose thead th {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--rule);
}

.prose tbody tr:last-child td {
  border-bottom: 1px solid var(--rule);
}

/* ----------------------------------------------------------- colophon
   The bill's small print at its foot: who posted it, how to follow it —
   the site's one visible RSS affordance. Sits at the bottom of the
   sheet even when the index above it is short. */

.notice {
  display: flex;
  flex-direction: column;
}

.colophon {
  margin-top: auto;
  padding-top: 1.3rem;
  border-top: 1px solid var(--rule);
}

.colophon-line {
  margin: 0 0 0.55em;
  font-family: var(--font-body);
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------ tear-tabs
   The bill's bottom edge is cut into a tear-off fringe (2026-07-08
   exploration round): FEED and EMAIL printed up each tab the way phone
   numbers ride a real flyer's fringe. Each tab is its own strip of the
   same paper (the main sheet stops above — --fringe on .notice), hangs
   with its own tiny lean, and two are already gone: a bill that never
   lost a tab was never read. */

.tabs {
  display: flex;
  align-items: flex-start;
  gap: 2px;
  height: var(--fringe, 5.1rem);
  margin-top: 1.1rem;
}

.tabs .tab {
  position: relative;
  flex: 1 1 0;
  height: 100%;
  background-color: var(--paper);
  background-image: var(--tex-paper);
  background-position: var(--tpx, 0) 78%;
  background-size: 700px;
  clip-path: var(--slip-edge);
  box-shadow:
    inset 0 0 10px var(--paste-soak),
    inset 0 -16px 20px -12px var(--paste-soak);
  transform: rotate(var(--trot, 0deg));
  transform-origin: top center;
  writing-mode: vertical-rl;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-decoration: none;
}

/* read bottom-up, like the reference fringe */
.tab .tab-text { transform: rotate(180deg); }

a.tab:hover, a.tab:focus-visible {
  color: var(--mark);
  box-shadow:
    inset 0 0 10px var(--paste-soak),
    inset 0 -16px 20px -12px var(--paste-soak),
    inset 0 0 0 999px rgba(255, 255, 255, 0.25);
}

/* a taken tab: only the glued stub above the tear survives */
.tabs .tab-taken {
  height: 1.3rem;
  background-color: var(--paper-deep);
  /* an irregular tear, not a sawtooth: varied depths, uneven spacing */
  clip-path: polygon(
    0 0, 100% 0, 100% 38%, 96% 71%, 89% 52%, 84% 88%, 79% 79%, 71% 100%,
    66% 62%, 58% 74%, 52% 48%, 47% 83%, 38% 68%, 33% 94%, 27% 51%,
    18% 77%, 12% 58%, 7% 90%, 3% 60%, 0 74%
  );
  box-shadow: inset 0 0 8px var(--paste-soak);
}

/* ------------------------------------------------------------ no bills
   A fresh wall, posted nowhere yet — still a finished page, not a
   broken empty list. */

.empty-notice {
  padding: 2.2rem 0;
  border-top: 1px solid var(--rule);
}

.empty-notice-label {
  margin: 0 0 0.8em;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.empty-notice-body {
  margin: 0;
  max-width: 30rem;
  font-family: var(--font-body);
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--ink);
}

.empty-notice-body a {
  color: var(--mark);
  text-decoration: underline;
  text-decoration-color: var(--mark-soft);
  text-underline-offset: 3px;
}

.empty-notice-body a:hover { text-decoration-color: var(--mark); }

/* -------------------------------------------------------------- mobile
   Nothing here may widen the sheet at phone width — the fixture's long
   code line and wide table both scroll inside their own box, never the
   page. */

@media (max-width: 700px) {
  .prose pre { font-size: 0.82rem; }
  .prose table { font-size: 0.86em; }
  .prose th, .prose td { padding-right: 0.9em; }
  .notes-list { font-size: 0.86em; }
}

/* --------------------------------------------------------------- motion
   Navigation is one camera move (reference/northstar/TRANSITION.md):
   stepping toward the wall (home → post, ~320ms) and stepping back
   (~240ms). Cross-document view transitions on plain links — browsers
   without support get instant navigation; reduced motion gets a plain
   swap. Direction types are stamped in the pageswap handler (shell). */

@view-transition {
  navigation: auto;
}

::view-transition-group(wall),
::view-transition-group(sheet),
::view-transition-group(post-title) {
  animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1);
  animation-duration: 0.32s;
}

::view-transition-old(wall),
::view-transition-new(wall),
::view-transition-old(sheet),
::view-transition-new(sheet) {
  animation-timing-function: cubic-bezier(0.2, 0.7, 0.2, 1);
  animation-duration: 0.32s;
  height: 100%;
  overflow: hidden;
}

/* the wall pushes in: outgoing wall scales up and gives way */
@keyframes wall-push { to { transform: scale(1.06); opacity: 0; } }
/* stepping back: outgoing wall recedes */
@keyframes wall-pull { to { transform: scale(0.96); opacity: 0; } }
/* paper arrives at reading distance: tiny settle, no flying cards */
@keyframes sheet-settle {
  from { transform: translateY(4px) scale(0.99); opacity: 0; }
  to { transform: translateY(0) scale(1); opacity: 1; }
}

html:active-view-transition-type(to-post)::view-transition-old(wall) {
  animation-name: wall-push;
}
html:active-view-transition-type(to-post)::view-transition-new(sheet) {
  animation-name: sheet-settle;
}

html:active-view-transition-type(to-home)::view-transition-old(wall) {
  animation-name: wall-pull;
}
html:active-view-transition-type(to-home)::view-transition-group(wall),
html:active-view-transition-type(to-home)::view-transition-old(wall),
html:active-view-transition-type(to-home)::view-transition-new(wall),
html:active-view-transition-type(to-home)::view-transition-group(sheet),
html:active-view-transition-type(to-home)::view-transition-old(sheet),
html:active-view-transition-type(to-home)::view-transition-new(sheet),
html:active-view-transition-type(to-home)::view-transition-group(post-title) {
  animation-duration: 0.24s;
}

/* the physical metaphor is never worth vestibular discomfort */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}
