/* Depth pass - the page should read as a sheet of stock on a surface, not as a
 * screen. All of it is CSS: no JS required, nothing to fail.
 *
 * Loads AFTER each page's inline <style>, so it can only add. Every value is
 * derived from tokens.css so a retheme still carries.
 */

:root {
  /* Laid-paper grain. The token exists in tokens.css and was set to `none` when
   * the gallery retheme landed; this is what it was designed to hold. Was two
   * octaves of feTurbulence - honest noise, but noise: it read as screen dither,
   * not as stock. Now a high-passed scan of real handmade laid paper, baked to a
   * dark-only RGBA at ~10% so it composites over ANY base colour exactly the way
   * the SVG did. High-passed on purpose: the large-scale mottle is stripped out,
   * so only the fibre tooth tiles, and the tile seam has nothing to show. */
  --paper-texture: url("ornament/paper-grain.png");

  /* The ageing that the grain deliberately lost - one un-tiled sheet, scaled to
   * cover, so the sheet is unevenly toned end to end with no repeat anywhere. */
  --paper-wash: url("ornament/paper-wash.jpg");

  --lift-sheet: 0 1px 2px rgba(28, 26, 23, .04), 0 12px 34px -14px rgba(28, 26, 23, .16);
  --lift-plate: 0 2px 4px rgba(28, 26, 23, .06), 0 22px 48px -22px rgba(28, 26, 23, .3);

  --ornament-ink: color-mix(in srgb, var(--color-accent-deep) 62%, var(--color-ink));
}

body {
  background-color: var(--color-paper-2);       /* the surface the sheet lies on */
  background-image: var(--paper-texture);
}

/* The frame is the sheet: its own stock, its own ageing, and a shadow so it sits
 * above the surface. Wash first so the grain tiles on top of it. */
.frame {
  position: relative;
  background-color: var(--color-paper);
  background-image: var(--paper-texture), var(--paper-wash);
  background-repeat: repeat, no-repeat;
  background-size: auto, cover;
  background-blend-mode: normal, multiply;
  box-shadow: var(--lift-sheet);
}

/* Engraved corner pieces, set into the four corners of the sheet. One pseudo
 * element carries all four - the same plate rotated, so the scrollwork turns the
 * corner instead of repeating. Sits under the content and never catches a click. */
.frame::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    url("ornament/ornament-corner-0.png"),
    url("ornament/ornament-corner-90.png"),
    url("ornament/ornament-corner-180.png"),
    url("ornament/ornament-corner-270.png");
  background-repeat: no-repeat;
  background-position: left top, right top, right bottom, left bottom;
  background-size: 92px auto;
  opacity: .42;
}
.frame > * { position: relative; z-index: 1; }
@media (max-width: 768px) { .frame::before { background-size: 54px auto; opacity: .3; } }

/* Letterpress: the type is struck INTO the paper, so the light catches the top
 * edge of the impression. One highlight, no dark shadow - a dark drop shadow
 * reads as embossed-upward and looks like a 2009 web template. */
h1, h2, .mark, .price, .bundle-price strong {
  text-shadow: 0 1px 0 rgba(255, 255, 255, .55);
}

/* Plates and product renders are objects resting on the sheet. */
.plate img, .hero figure img, figure.scan img,
img[src*="plates/"], img[src*="scans/"] {
  box-shadow: var(--lift-plate);
  background: var(--color-paper-3);
}

/* The printer's device: the mark that stood on a title page before the title did.
 * Deliberately small - it is the hero's anchor, not the hero. No box-shadow: these
 * are keyed transparent PNGs, so a shadow would draw a rectangle around nothing. */
.hero .device {
  display: block;
  margin: var(--space-sm) auto 0;
  height: clamp(132px, 21vw, 208px);
  width: auto;
  max-width: 100%;
  opacity: .92;
}

/* Product cards led with a heading on bare stock, which is what made them read as
 * boxes. Each now opens with its own engraved plate, keyed to the same ink. */
.card .cardplate {
  display: block;
  width: 100%;
  max-width: 260px;
  height: auto;
  margin: 0 auto var(--space-xs);
  opacity: .9;
}

/* Cards lift very slightly, and further on hover - the only motion in this file. */
.card {
  background: var(--color-paper-3) var(--paper-texture);
  box-shadow: var(--lift-sheet);
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
.card:hover {
  transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(28, 26, 23, .05), 0 20px 44px -18px rgba(28, 26, 23, .26);
}

.orderbox, .bundle, .guarantee, .cta, blockquote {
  background-color: var(--color-paper-3);
  background-image: var(--paper-texture);
}

/* A rule should look like an impression in the sheet, not a 1px line. */
.band { border-top-color: color-mix(in srgb, var(--color-rule) 78%, transparent); }

/* Section break: an engraved fleuron sitting on the hairline, the way a printer
 * would break a chapter. The rule itself stays - the ornament is set over its
 * midpoint, masked in the accent so it reads as one impression, not a pasted GIF.
 * mask + background-color rather than an <img> so the ink follows the theme token. */
section.band { position: relative; }
section.band::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: min(340px, 64%);
  aspect-ratio: 1200 / 224;   /* the plate's true ink bounds - contain does the rest */
  transform: translate(-50%, -50%);
  background-color: var(--ornament-ink);
  -webkit-mask: url("ornament/ornament-rule.png") center / contain no-repeat;
  mask: url("ornament/ornament-rule.png") center / contain no-repeat;
  opacity: .62;
  pointer-events: none;
}
/* The ornament needs the sheet behind it, not the hairline running through the
 * scrollwork. A short blank gap centred on the rule does it with no extra node. */
section.band::after {
  content: "";
  position: absolute;
  top: -1px;
  left: 50%;
  width: min(324px, 63%);
  height: 2px;
  transform: translateX(-50%);
  background: var(--color-paper);
  pointer-events: none;
}
/* Pages that open with a band directly under the nav already have the nav rule. */
nav + section.band::before, nav + section.band::after { display: none; }

@media (prefers-reduced-motion: reduce) {
  .card { transition: none; }
  .card:hover { transform: none; }
}

/* Print: strip the staging. The document is the thing being printed, not a page. */
@media print {
  body { background: #fff; }
  .frame { box-shadow: none; background: #fff; }
  .plate img, .hero figure img, figure.scan img,
  img[src*="plates/"], img[src*="scans/"] { box-shadow: none; }
  h1, h2, .mark, .price { text-shadow: none; }
}

/* Comparison table - lived only in the product pages' inline styles; hoisted here
 * so any page can use it (the index counter-positioning table needs it). */
table.compare { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
table.compare th, table.compare td {
  border-bottom: var(--rule-hairline); padding: 10px 8px; text-align: left; vertical-align: top; }
table.compare thead th {
  font-family: var(--font-caps); letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--color-accent-deep); border-bottom: 2px solid var(--color-accent); }
table.compare tbody th { font-weight: 400; font-family: var(--font-body); }
table.compare td.own {
  background: var(--color-paper-3); color: var(--color-ink); }
table.compare td.other { color: var(--color-ink-dim); font-style: italic; }
@media (max-width: 860px) { table.compare { display: block; overflow-x: auto; } }

/* The product pages uppercase td.own because those cells hold one word ("yes").
 * The counter-positioning table holds sentences, where all-caps is unreadable. */
table.compare.verdict td.own { text-transform: none; letter-spacing: normal;
  font-family: var(--font-body); }

/* Scroll-driven reveal. Native animation-timeline only - no library, no JS. Lived
 * in the product pages' inline <style> (twice, verbatim) and was shadowed there by
 * GSAP + ScrollTrigger off a CDN doing the same job. Hoisted here so every page -
 * blog and book included - gets the motion from one 0-byte-of-JS source.
 *
 * Guarded twice: browsers without view() support and readers who ask for less
 * motion get the static page, never a blank one. Nothing here sets opacity:0
 * outside the guard, so content never depends on animation to be visible. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    @keyframes slide-in {
      from { opacity: 0; transform: translate3d(var(--slide-from, 0), 30px, 0); }
      to   { opacity: 1; transform: none; }
    }
    @keyframes plate-rise {
      from { opacity: 0.55; transform: translate3d(0, 34px, 0) scale(0.965); }
      to   { opacity: 1; transform: none; }
    }
    section.band > h2, section.band > .eyebrow, .grid3 > *, .grid2 > *, .qual > *,
    .steps > *, .plate figure, .orderbox, .guarantee, .bundle, .trust li,
    table.compare, .sources li, .register, .postlist .entry, .cta {
      animation: slide-in linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 26%;
      will-change: opacity, transform;
    }
    /* Specimen plates slide in from opposite edges - the product is the hero here. */
    .plate figure:nth-child(odd) { --slide-from: -26px; }
    .plate figure:nth-child(even) { --slide-from: 26px; }
    /* Stagger anything that enters as a row, so it reads as a deal, not a jump. */
    .grid3 > *:nth-child(2), .grid2 > *:nth-child(2), .trust li:nth-child(2),
    .steps > *:nth-child(2) { animation-range: entry 4% cover 32%; }
    .grid3 > *:nth-child(3), .trust li:nth-child(3), .steps > *:nth-child(3) { animation-range: entry 4% cover 38%; }
    .trust li:nth-child(4) { animation-range: entry 4% cover 44%; }
    .hero figure img { animation: plate-rise linear both; animation-timeline: view(); animation-range: entry 0% cover 45%; }
    /* The order box and the bundle are the close - let them arrive later and firmer. */
    .orderbox, .bundle, .guarantee { animation-range: entry 8% cover 34%; }

    /* Plates drift against the scroll - 1801 engravings on a moving sheet. Replaces
     * the GSAP parallax tween. `translate`, not `transform`, so it composes with the
     * slide-in on the figure wrapping it instead of clobbering it. Small on purpose:
     * felt, not noticed. */
    @keyframes plate-drift { from { translate: 0 -2.2%; } to { translate: 0 2.2%; } }
    img[src*="plates/"], img[src*="scans/"], figure.scan img {
      animation: plate-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
  }
}
