/* ==========================================================================
   Zine Rack — collage layer

   Loads LAST, on top of zinerack.css (tokens) and zinerack-app.css (skin).
   Everything here is decoration: torn paper, washi tape, stamps, doodles and
   the night-city ground. It is deliberately one file and one <link> so the
   whole maximalist pass can be removed in a single line if it is too much.

   Two rules hold the whole layer together:

   1. DECORATION NEVER CLIPS OR CATCHES. Every ornament is a pseudo-element or
      an aria-hidden node with `pointer-events: none`. Nothing here is in the
      accessibility tree and nothing intercepts a click.

   2. A CREATOR'S RACK IS THEIR CANVAS. Everything in this file switches off
      inside `.rack-themed`. The site's scrapbook stops at the edge of
      somebody else's zine table (claude.md rule 4).

   Note on pseudo-element budget: `clip-path` and `mask` clip an element's own
   pseudo-elements, so the torn paper lives on ::before (behind the content,
   via an isolated stacking context) and the tape on ::after (above it). They
   can never be the same element — that mistake shipped once already.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Shared shapes
   -------------------------------------------------------------------------- */

:root {
  /* A torn top-and-bottom mask: opaque through the middle, ragged at both
     edges. Used by every paper panel. */
  --zr-torn-mask:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 10' preserveAspectRatio='none'%3E%3Cpath d='M0 10h400V4.8c-8 3.1-15 1-23 -.7s-16-1.9-24 .5-16 3.6-24 1.2-16-4.1-24-2.8-16 4.1-24 4.8-16-1.2-24-2.8-16-.3-24 1.4-16 2.8-24 1-16-4.4-24-3.9-16 3-24 4.4-16 .5-24-1-16-2.6-24-1.2-16 3.3-24 3.7-16-1.5-23-3.2z' fill='%23fff'/%3E%3C/svg%3E");
  --zr-torn-mask-b:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 10' preserveAspectRatio='none'%3E%3Cpath d='M0 0h400v5.2c-8-3.1-15-1-23 .7s-16 1.9-24-.5-16-3.6-24-1.2-16 4.1-24 2.8-16-4.1-24-4.8-16 1.2-24 2.8-16 .3-24-1.4-16-2.8-24-1-16 4.4-24 3.9-16-3-24-4.4-16-.5-24 1-16 2.6-24 1.2-16-3.3-24-3.7-16 1.5-23 3.2z' fill='%23fff'/%3E%3C/svg%3E");

  /* The randomiser assigns these per element; the values here are the
     no-JavaScript fallback. */
  --tape:  url("../img/tape/tape-violet-speckle.webp");
  --paper: var(--zr-paper-dark);
  --tilt:  0deg;
}

/* --------------------------------------------------------------------------
   The night city

   One pre-composed, horizontally tiling WebP for the skyline and one for the
   stars. Composed rather than assembled in CSS because both are identical on
   every page and every visit — this is the part that should be a single
   cached fetch. The parts that SHOULD differ per visit stay separate assets
   the randomiser deals out.
   -------------------------------------------------------------------------- */

.page-deco {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}

.page-deco__stars {
  position: absolute;
  inset: 0;
  background-image: url("../img/texture/stars.webp");
  background-size: 700px 700px;
  background-repeat: repeat;
  opacity: .55;
}

.page-deco__city {
  position: absolute;
  left: 0; right: 0;
  top: 190px;
  height: 300px;
  background-image: url("../img/texture/skyline.webp");
  background-size: 1600px 300px;
  background-repeat: repeat-x;
  background-position: bottom left;
  opacity: .9;
  /* Fade IN from the top: the artwork is transparent sky at the top and solid
     buildings at the bottom, so the gradient must reach full opacity before it
     meets the rooflines. The other way round erased the ground line and the
     base of every building. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 42%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 42%);
}

/* The body's own grain stays; the flat radial wash gives way to the city.
   Guarded, because zinerack.css lowers this same declaration under
   prefers-reduced-transparency at equal specificity — unguarded, this later
   stylesheet wins inside that media query too and hands the viewer who asked
   for LESS transparency nearly double the grain. */
@media not all and (prefers-reduced-transparency: reduce) {
  body::after { opacity: .22; }
}

@media (max-width: 860px) {
  .page-deco__city { top: 150px; height: 210px; background-size: 1100px 210px; }
}

/* --------------------------------------------------------------------------
   Panels as torn paper

   `.card` keeps its box (padding, layout, borders off) but its visible
   surface moves to ::before, which carries the handmade-paper texture and the
   torn mask. `isolation: isolate` makes the card a stacking context so that
   layer can sit at z-index -1 — behind the card's own content, but not behind
   the page.
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  isolation: isolate;
  background: none;
  background-image: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: var(--zr-6) var(--zr-6) var(--zr-5);
  transform: rotate(var(--tilt));
}

.card::before {
  content: "";
  position: absolute;
  inset: -2px 0;
  z-index: -1;
  background-color: #1A2131;
  background-image: var(--paper);
  background-size: 300px auto;
  background-blend-mode: soft-light;
  border-left: 1px solid rgba(243,239,230,.14);
  border-right: 1px solid rgba(243,239,230,.14);
  -webkit-mask-image: var(--zr-torn-mask), linear-gradient(#000, #000), var(--zr-torn-mask-b);
  mask-image: var(--zr-torn-mask), linear-gradient(#000, #000), var(--zr-torn-mask-b);
  -webkit-mask-size: 400px 10px, 100% calc(100% - 20px), 400px 10px;
  mask-size: 400px 10px, 100% calc(100% - 20px), 400px 10px;
  -webkit-mask-repeat: repeat-x, no-repeat, repeat-x;
  mask-repeat: repeat-x, no-repeat, repeat-x;
  -webkit-mask-position: top left, left 10px, bottom left;
  mask-position: top left, left 10px, bottom left;
  /* Tight shadow only: a wide blur bled between neighbouring cards and read
     as one continuous band instead of separate scraps on a shelf. */
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.6)) drop-shadow(0 6px 12px rgba(0,0,0,.35));
}

/* Tape. ::after so the panel's own mask can never clip it. */
.card::after {
  content: "";
  position: absolute;
  z-index: 3;
  width: var(--tape-w, 96px);
  height: var(--tape-h, 27px);
  top: -13px;
  left: var(--tape-x, -16px);
  right: var(--tape-r, auto);
  background-image: var(--tape);
  background-size: 100% 100%;
  background-repeat: no-repeat;
  transform: rotate(var(--tape-rot, -23deg));
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.55));
  opacity: .95;
  pointer-events: none;
}

/* Deterministic fallback when the randomiser has not run: still a collage,
   just the same one every time. */
.card:nth-of-type(3n+1) { --tape: url("../img/tape/tape-kraft-speckle.webp"); --tilt: -.5deg; }
.card:nth-of-type(3n+2) { --tape: url("../img/tape/tape-star-navy.webp");
                          --tape-x: auto; --tape-r: -16px; --tape-rot: 21deg; --tilt: .45deg; }
.card:nth-of-type(3n+3) { --tape: url("../img/tape/tape-grid.webp"); --tilt: -.3deg; }
.card:nth-of-type(4n+1) { --paper: var(--zr-paper-griddk); }
.card:nth-of-type(5n+3) { --paper: url("../img/paper/tile-crumple-dark.webp"); }

.grid > .card:hover { transform: rotate(0deg) translateY(-4px); }
.grid > .card { transition: transform var(--zr-med) var(--zr-ease); }

/* --------------------------------------------------------------------------
   Section headings as paper labels

   The guide's "New & Noteworthy" and "Nearby Zines" sit on a light strip of
   paper with dark ink. h1 keeps its full-width display treatment.
   -------------------------------------------------------------------------- */

main > h2,
main > h3,
main > .band > h2 {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--zr-2);
  padding: 5px var(--zr-5) 6px;
  margin-left: 2px;
  color: var(--zr-ink);
  background-color: var(--zr-paper-mid);
  background-image: var(--zr-paper-ledger);
  background-size: 190px auto;
  background-blend-mode: multiply;
  font-family: var(--zr-font-display);
  letter-spacing: var(--zr-track-display);
  text-transform: uppercase;
  transform: rotate(-.7deg);
  box-shadow: 0 2px 5px rgba(0,0,0,.5);
  -webkit-mask-image: var(--zr-torn-mask), linear-gradient(#000, #000), var(--zr-torn-mask-b);
  mask-image: var(--zr-torn-mask), linear-gradient(#000, #000), var(--zr-torn-mask-b);
  -webkit-mask-size: 400px 8px, 100% calc(100% - 16px), 400px 8px;
  mask-size: 400px 8px, 100% calc(100% - 16px), 400px 8px;
  -webkit-mask-repeat: repeat-x, no-repeat, repeat-x;
  mask-repeat: repeat-x, no-repeat, repeat-x;
  -webkit-mask-position: top left, left 8px, bottom left;
  mask-position: top left, left 8px, bottom left;
}
/* The dotted trailing rule was an ::after on h3; the mask above would clip it,
   so the label simply ends. */
main > h3::after { display: none; }
main > h2, main > .band > h2 { font-size: var(--zr-fs-lg); }
main > h3 { font-size: var(--zr-fs-base); color: var(--zr-ink); }

/* --------------------------------------------------------------------------
   Cover thumbnails as photographs

   A cream paper mount with a dark rebate, the way a printed zine cover sits
   in the guide.
   -------------------------------------------------------------------------- */

.thumb, .cover, .rack-strip-img {
  border: 3px solid var(--zr-paper);
  border-radius: 1px;
  box-shadow: 0 2px 4px rgba(0,0,0,.6), 0 10px 24px rgba(0,0,0,.4);
}
.thumb { margin-bottom: var(--zr-4); }

/* A gold corner star on the first cover of any grid — the guide's "seal". */
.card > a:first-child { position: relative; display: block; }

/* --------------------------------------------------------------------------
   Controls
   -------------------------------------------------------------------------- */

/* Secondary actions read as kraft paper labels, like the guide's
   Stamp / Save / Share row. Primary stays violet so the main action is still
   unmistakably the main action. */
button.secondary, .btn.secondary, .secondary {
  background-color: var(--zr-paper-mid);
  background-image: var(--zr-paper-ledger);
  background-size: 170px auto;
  background-blend-mode: multiply;
  color: var(--zr-ink);
  border: 0;
  border-radius: 2px;
  font-family: var(--zr-font-display);
  letter-spacing: var(--zr-track-display);
  box-shadow: 0 2px 4px rgba(0,0,0,.5);
  transform: rotate(var(--btn-tilt, -1deg));
}
button.secondary:hover, .btn.secondary:hover, .secondary:hover {
  background-color: var(--zr-paper);
  color: var(--zr-ink);
  transform: rotate(0deg) translateY(-1px);
}
/* The × inside a tag is a .secondary button; keep it a glyph, not a label. */
.tag button.secondary, .tag .secondary {
  background: none;
  box-shadow: none;
  color: var(--zr-text-faint);
  transform: none;
  font-family: var(--zr-font-body);
}

/* Primary: a violet paper chip with a torn edge. */
button, .btn {
  border-radius: 2px;
  transform: rotate(var(--btn-tilt, -.6deg));
}
button:hover, .btn:hover { transform: rotate(0deg) translateY(-1px); }
/* .linky is a bare text button ("use default") in the rack theme editor. A
   rotated text link reads as a rendering fault, not as collage. */
.linky, .linky:hover { transform: none; }

/* Tags become little punched paper chips. */
.tag {
  border-radius: 2px;
  background-color: rgba(243,239,230,.07);
  transform: rotate(var(--chip-tilt, 0deg));
  margin: 2px 3px;
}
.tag.ai { box-shadow: 0 1px 3px rgba(0,0,0,.5); }

/* Django messages become a taped paper note. */
.messages li {
  position: relative;
  background-color: var(--zr-paper);
  background-image: var(--zr-paper-cream);
  background-size: 240px auto;
  background-blend-mode: multiply;
  color: var(--zr-ink);
  border: 0;
  border-left: 0;
  border-radius: 0;
  padding: var(--zr-4) var(--zr-6);
  transform: rotate(-.5deg);
  box-shadow: var(--zr-shadow);
  -webkit-mask-image: var(--zr-torn-mask), linear-gradient(#000, #000), var(--zr-torn-mask-b);
  mask-image: var(--zr-torn-mask), linear-gradient(#000, #000), var(--zr-torn-mask-b);
  -webkit-mask-size: 400px 9px, 100% calc(100% - 18px), 400px 9px;
  mask-size: 400px 9px, 100% calc(100% - 18px), 400px 9px;
  -webkit-mask-repeat: repeat-x, no-repeat, repeat-x;
  mask-repeat: repeat-x, no-repeat, repeat-x;
  -webkit-mask-position: top left, left 9px, bottom left;
  mask-position: top left, left 9px, bottom left;
}

/* --------------------------------------------------------------------------
   Scattered ornament

   The randomiser appends these into `.deco-field`, one per page margin. They
   are absolutely positioned, aria-hidden and non-interactive.
   -------------------------------------------------------------------------- */

body { position: relative; }

.deco-field {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;   /* ornament in the gutters can never widen the page */
}
main         { position: relative; z-index: 1; }
.site-footer { position: relative; z-index: 1; }

/* Below this width the gutters are too narrow to hold a stamp without it
   colliding with the text. The randomiser checks the real gutter too. */
@media (max-width: 1180px) { .deco-field { display: none; } }

.deco {
  position: absolute;
  pointer-events: none;
  user-select: none;
}
.deco img { display: block; width: 100%; height: auto; }
.deco--stamp  { width: 76px;  filter: drop-shadow(0 3px 7px rgba(0,0,0,.6)); opacity: .92; }
.deco--eph    { width: 104px; filter: drop-shadow(0 3px 6px rgba(0,0,0,.55)); opacity: .9; }
.deco--tape   { width: 128px; filter: drop-shadow(0 2px 4px rgba(0,0,0,.5)); opacity: .8; }
.deco--doodle { color: var(--zr-paper-dim); opacity: .4; }
.deco--doodle svg { width: 100%; height: auto; display: block; }
.deco--gold   { color: var(--zr-gold); opacity: .55; }

/* --------------------------------------------------------------------------
   Header and footer trimmings
   -------------------------------------------------------------------------- */

header {
  border-bottom: 0;
  background: linear-gradient(to bottom, rgba(11,14,20,.94), rgba(11,14,20,.82));
}
header::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -9px;
  height: 10px;
  background: rgba(11,14,20,.88);
  -webkit-mask-image: var(--zr-torn-mask-b);
  mask-image: var(--zr-torn-mask-b);
  -webkit-mask-size: 400px 10px;
  mask-size: 400px 10px;
  -webkit-mask-repeat: repeat-x;
  mask-repeat: repeat-x;
  pointer-events: none;
}

.site-footer {
  border-top: 0;
  position: relative;
}
.site-footer::before {
  content: "";
  pointer-events: none;
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 10px;
  background: rgba(243,239,230,.07);
  -webkit-mask-image: var(--zr-torn-mask);
  mask-image: var(--zr-torn-mask);
  -webkit-mask-size: 400px 10px;
  mask-size: 400px 10px;
  -webkit-mask-repeat: repeat-x;
  mask-repeat: repeat-x;
}

/* --------------------------------------------------------------------------
   A creator's rack keeps none of this
   -------------------------------------------------------------------------- */

.rack-themed .card {
  transform: none;
  background: transparent;
  padding: var(--zr-5);
  /* The collage zeroes `border` and `border-radius` on every .card. The skin's
     .rack-themed override only ever set border-COLOR, so a creator's cards were
     left with neither fill nor outline — nothing separated them at all. */
  border: 1px solid currentColor;
  border-radius: var(--zr-r);
}
.rack-themed .card::before,
.rack-themed .card::after { display: none; }
.rack-themed .deco-field { display: none; }
.rack-themed h2, .rack-themed h3,
.rack-themed main > h2, .rack-themed main > h3 {
  background: none;
  color: inherit;
  transform: none;
  padding: 0;
  -webkit-mask-image: none;
  mask-image: none;
  box-shadow: none;
  text-transform: none;
}
.rack-themed .thumb, .rack-themed .cover, .rack-themed .rack-strip-img {
  border-color: currentColor;
  border-width: 2px;
  /* A 24px near-black blur belongs on the night chrome, not on somebody's
     white rack. */
  box-shadow: none;
  border-radius: var(--zr-r-sm);
}
.rack-themed .thumb { margin-bottom: var(--zr-3); }
.rack-themed button, .rack-themed .btn {
  transform: none;
  background-image: none;
  font-family: var(--rack-font, inherit);
  box-shadow: none;
}
/* Same trap as the card: the collage sets `border: 0` on .secondary, and the
   skin's override only restores border-color — so Like / Share / Follow lost
   their outline and became bare text on the creator's page. */
.rack-themed button.secondary,
.rack-themed .btn.secondary,
.rack-themed .secondary {
  transform: none;
  background-image: none;
  font-family: var(--rack-font, inherit);
  box-shadow: none;
  border: 1px solid currentColor;
}
.rack-themed .tag,
.rack-themed .tag.ai { transform: none; box-shadow: none; }

/* ==========================================================================
   The deck the randomiser deals from

   Class names only — every URL lives here, so zinerack-collage.js never needs
   to know where the static root is.
   ========================================================================== */

.tape-1  { --tape: url("../img/tape/tape-kraft-speckle.webp"); }
.tape-2  { --tape: url("../img/tape/tape-grid.webp"); }
.tape-3  { --tape: url("../img/tape/tape-night-moon.webp"); }
.tape-4  { --tape: url("../img/tape/tape-violet-speckle.webp"); }
.tape-5  { --tape: url("../img/tape/tape-star-navy.webp"); }
.tape-6  { --tape: url("../img/tape/tape-star-dark.webp"); }
.tape-7  { --tape: url("../img/tape/tape-floral.webp"); }
.tape-8  { --tape: url("../img/tape/tape-botanical.webp"); }
.tape-9  { --tape: url("../img/tape/tape-music.webp"); }
.tape-10 { --tape: url("../img/tape/tape-linen-light.webp"); }
.tape-11 { --tape: url("../img/tape/tape-burlap.webp"); }
.tape-12 { --tape: url("../img/tape/tape-violet-star.webp"); }

.paper-1 { --paper: var(--zr-paper-dark); }
.paper-2 { --paper: var(--zr-paper-griddk); }
.paper-3 { --paper: url("../img/paper/tile-crumple-dark.webp"); }
.paper-4 { --paper: url("../img/paper/tile-violet.webp"); }
.paper-5 { --paper: url("../img/paper/tile-violet-grid.webp"); }

/* Where the tape was pressed down. These are CLASSES, not inline values, so
   the mobile block below can still override them — an inline style from the
   randomiser would beat any media query and push the tape off-screen. */
.tapepos-a::after { top: -13px; left: -16px; right: auto; width: 96px;  height: 27px;
                    transform: rotate(-23deg); }
.tapepos-b::after { top: -13px; left: auto;  right: -15px; width: 104px; height: 28px;
                    transform: rotate(21deg); }
.tapepos-c::after { top: -12px; left: 50%;   right: auto; width: 126px; height: 30px;
                    transform: translateX(-50%) rotate(-2deg); }
.tapepos-d::after { top: -9px;  left: -22px; right: auto; width: 88px;  height: 25px;
                    transform: rotate(-38deg); }
.tapepos-e::after { top: -11px; left: auto;  right: 24px; width: 84px;  height: 24px;
                    transform: rotate(13deg); }

/* Scattered ornament, as background images so the markup stays a bare span. */
.deco--stamp, .deco--eph, .deco--tape {
  background-size: 100% 100%;
  background-repeat: no-repeat;
}
.deco--stamp { aspect-ratio: 3 / 4; }
.deco--eph   { aspect-ratio: 5 / 3; }
.deco--tape  { aspect-ratio: 22 / 5; }

.st-night-moon  { background-image: url("../img/stamps/stamp-night-moon.webp"); }
.st-flower      { background-image: url("../img/stamps/stamp-flower.webp"); }
.st-owl         { background-image: url("../img/stamps/stamp-owl.webp"); }
.st-moon-violet { background-image: url("../img/stamps/stamp-moon-violet.webp"); aspect-ratio: 15/8; }
.st-library     { background-image: url("../img/stamps/stamp-library-date-due.webp"); aspect-ratio: 2/1; }
.st-moth        { background-image: url("../img/stamps/stamp-moth.webp"); aspect-ratio: 2/1; }

.ep-ticket { background-image: url("../img/ephemera/ticket-night-bus.webp"); aspect-ratio: 9/5; }
.ep-tag    { background-image: url("../img/ephemera/tag-kraft.webp"); aspect-ratio: 5/8; }
.ep-handle { background-image: url("../img/ephemera/label-handle-with-care.webp"); aspect-ratio: 9/4; }
.ep-note   { background-image: url("../img/ephemera/note-be-kind.webp"); aspect-ratio: 2/1; }
.ep-keep   { background-image: url("../img/ephemera/label-keep-going.webp"); aspect-ratio: 3/1; }
.ep-date   { background-image: url("../img/ephemera/label-date.webp"); aspect-ratio: 5/3; }
.ep-arrow  { background-image: url("../img/ephemera/arrow-this-way.webp"); aspect-ratio: 5/2; }
.ep-seal   { background-image: url("../img/ephemera/seal-moth.webp"); aspect-ratio: 1/1; }
.ep-moon   { background-image: url("../img/ephemera/label-moon.webp"); aspect-ratio: 4/3; }

.tp-kraft  { background-image: url("../img/tape/tape-kraft-speckle.webp"); }
.tp-grid   { background-image: url("../img/tape/tape-grid.webp"); }
.tp-night  { background-image: url("../img/tape/tape-night-moon.webp"); }
.tp-violet { background-image: url("../img/tape/tape-violet-speckle.webp"); }
.tp-star   { background-image: url("../img/tape/tape-star-navy.webp"); }
.tp-floral { background-image: url("../img/tape/tape-floral.webp"); }
.tp-music  { background-image: url("../img/tape/tape-music.webp"); }
.tp-linen  { background-image: url("../img/tape/tape-linen-light.webp"); }


/* ==========================================================================
   Responsive and preference overrides — LAST ON PURPOSE

   These undo declarations made above at the same specificity, so they only
   win by source order. Anything added after this point that touches the same
   selectors will silently beat them: the tape position classes were appended
   below this block once, and on a phone `.tapepos-b::after { right: -15px }`
   put the tape 15px past the right-hand card and gave the page a horizontal
   scrollbar.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Restraint where it is owed
   -------------------------------------------------------------------------- */

@media (max-width: 860px) {
  /* Mobile stays clean and easy to read — the guide's own rule. The collage
     survives as texture and tape; the tilt and the scattered ornament do not. */
  .card { transform: none; padding: var(--zr-5) var(--zr-4); }
  /* Tucked inside the card's own edge so no ornament can widen the page. */
  .card::after,
  .tapepos-a::after, .tapepos-b::after, .tapepos-c::after,
  .tapepos-d::after, .tapepos-e::after {
    top: -9px; left: 6px; right: auto;
    width: 72px; height: 20px;
    transform: rotate(-11deg);
  }
  .deco-field { display: none; }
  main > h2, main > h3 { transform: none; }
  /* Every inline custom property the randomiser sets must be neutralised
     here — an inline style beats a media query, so anything left rotating
     stays rotated on a phone. .tag was missed on the first pass. */
  button, .btn, .secondary, .tag { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .grid > .card:hover { transform: rotate(var(--tilt)); }
}

/* Someone who has asked for less visual noise gets the layout without the
   scrapbook: no scattered ornament, no tape, no tilt. */
@media (prefers-reduced-transparency: reduce) {
  .deco-field { display: none; }
  .card::after { display: none; }
  .card { transform: none; }
}

@media print {
  .page-deco, .deco-field, .card::after { display: none !important; }
  .card::before { filter: none; }
}
