/* ==========================================================================
   TELL — ui-paper.css · the paper redress token layer
   ==========================================================================
   design/50-ui-redress.md §3 (palette, type, restraint) and §4 (the asset kit).

   Loaded AFTER theme.css so it may extend the Harbor Noir tokens; it does not
   restyle any existing component. Everything here is a token, a @font-face, or
   a primitive (.paper-lift, .paper-plate) that the R1b/R2 chrome consumes.

   Three laws encoded here:
   1. Every plate is BLANK. All lettering is runtime type drawn over the top —
      never baked into an asset.
   2. ONE saturated element per screen: --pp-red. Nothing else in chrome is
      allowed to be saturated, and character accent hues stay reserved for
      story art.
   3. No red/green semantics anywhere near choices. --pp-red is thread, pin and
      stamp — it never marks an option as right or wrong.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Self-hosted faces. No CDN — both are SIL OFL 1.1, sources and licences in
   assets/fonts/ (LICENSE-CourierPrime-OFL.txt, LICENSE-Caveat-OFL.txt).
   font-display: swap so a slow font never gates a reveal.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Courier Prime';
  src: url('../assets/fonts/CourierPrime-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Courier Prime';
  src: url('../assets/fonts/CourierPrime-Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Courier Prime';
  src: url('../assets/fonts/CourierPrime-Italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
/* Caveat ships as a variable face (wght 400–700) — one file covers both. */
@font-face {
  font-family: 'Caveat';
  src: url('../assets/fonts/Caveat.woff2') format('woff2-variations'),
       url('../assets/fonts/Caveat.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* --- §3 grounds ----------------------------------------------------- */
  --pp-ink: #0b1220;            /* Harbor Ink — the game's dark             */
  --pp-wood: #4a3524;           /* desk-wood umber (desk-edge plate mid)    */
  --pp-wood-deep: #241a12;      /* desk shadow                              */
  --pp-cork: #9a7743;           /* cork tan (cork-wall plate mid)           */
  --pp-cork-deep: #5d452a;      /* cork in shadow / un-sunned patch base    */

  /* --- §3 papers ------------------------------------------------------- */
  --pp-manila: #c9b489;         /* folders, tabs                            */
  --pp-ledger: #e8dfc9;         /* ledger cream — codex + READ ground       */
  --pp-card: #ede6d6;           /* card white-warm — index cards, receipts  */

  /* --- §3 marks -------------------------------------------------------- */
  --pp-graphite: #3a3f45;       /* pencil — steno pad, marginalia           */
  --pp-type: #22242b;           /* typewriter ink — labels, receipts        */
  --pp-stamp-blue: #2b3a55;     /* stamp blue-black — secondary stamps      */

  /* --- §3 THE one saturated element ------------------------------------ */
  --pp-red: #8e2f2a;            /* thread / stamp / ribbon — dried blood    */
  --pp-red-dim: rgba(142, 47, 42, 0.55);

  /* --- derived ink levels for type ON paper ---------------------------- */
  --pp-type-dim: rgba(34, 36, 43, 0.62);
  --pp-type-faint: rgba(34, 36, 43, 0.34);
  --pp-rule: rgba(43, 58, 85, 0.28);   /* printed ruling / underlines       */

  /* --- §3 type --------------------------------------------------------- */
  /* Typewriter — labels, stamps, receipts, card titles, drawer tabs.       */
  --font-type: 'Courier Prime', 'Courier New', Courier,
               ui-monospace, 'Cascadia Mono', 'DejaVu Sans Mono', monospace;
  /* Hand-adjacent — marginalia, pencil-written choice lines.               */
  --font-hand: 'Caveat', 'Segoe Script', 'Bradley Hand', 'Comic Sans MS',
               'Apple Chancery', cursive;
  /* Body/reading text is unchanged: theme.css --font-prose still rules.    */
  --fs-stamp: clamp(0.72rem, 1.5vw, 0.95rem);
  --track-stamp: 0.30em;        /* stamps are letterspaced, always caps     */
  --track-type: 0.06em;

  /* --- §4 plates ------------------------------------------------------- */
  /* Every one BLANK by law. Sizes are the generated targets.
     FOUR carry a real alpha channel because they get composited ONTO another
     painted surface (the cork wall / a page): card-face, card-back, receipt,
     pin-sprites. Their drop shadow is NOT baked — use --pp-shadow-* so the
     lift is a CSS fact, per §3. The other twelve are opaque plates on their own
     ground and want `background-image`, not an <img> over cork.
     Machine-readable inventory: assets/ui/MANIFEST.json.               */
  --plate-cork-wall: url('../assets/ui/cork-wall.webp');       /* 1600x900  */
  --plate-card-face: url('../assets/ui/card-face.webp');       /*  640x420 a */
  --plate-card-back: url('../assets/ui/card-back.webp');       /*  640x420 a */
  --plate-folder: url('../assets/ui/folder.png');              /*  900x640  */
  --plate-folder-open: url('../assets/ui/folder-open.png');    /*  900x640  */
  --plate-ledger-spread: url('../assets/ui/ledger-spread.webp');/*1600x1000 */
  --plate-book-cover: url('../assets/ui/book-cover.webp');     /* 1050x1406 */
  --plate-book-open: url('../assets/ui/book-open.webp');       /* 1600x1000 */
  /* TRUE-ALPHA cut-outs of the same two objects (magenta-key recipe, the
     pin-sprites precedent): the book silhouette only, transparent everywhere
     else, no baked ground and no baked shadow. Owner ruling 2026-08-10: the
     opaque plates above read as "a rectangle cropped out of another photo laid
     over the desk" — you can see the seam where the plate's own dark ground
     meets the wood. These replace them the moment they exist; the title's
     swap block (index.html, "THE BOOK'S IMAGERY LIVES HERE") is the only
     consumer, and the grounding becomes --pp-shadow-contact alone.
     Declared ahead of the files so the swap is one edit in one place. */
  --plate-book-cover-cut: url('../assets/ui/book-cover-cut.webp');
  --plate-book-open-cut: url('../assets/ui/book-open-cut.webp');
  --plate-desk-top: url('../assets/ui/desk-top.webp');         /* 1600x900  */
  --plate-steno-pad: url('../assets/ui/steno-pad.png');        /*  900x700  */
  --plate-desk-edge: url('../assets/ui/desk-edge.png');        /* 1600x140  */
  --plate-index-card: url('../assets/ui/index-card-pinned.png');/* 800x560  */
  --plate-stamp-ring: url('../assets/ui/stamp-ring.png');      /*  500x220  */
  --plate-receipt: url('../assets/ui/receipt.webp');           /*  420x900 a */
  --plate-pin-sprites: url('../assets/ui/pin-sprites.png');    /*  800x400 a */
  --plate-rain-vignette: url('../assets/ui/rain-vignette.webp');/*1600x900  */

  /* --- §4 wave-1 additions (2026-08-31) ---------------------------------
     Seven more plates, same law: BLANK, FLAT-LIT, no baked shadow. Six carry
     true alpha (the magenta-key recipe, same as the -cut pair above); only
     caption-strip is an opaque full-bleed painting. DECLARED ONLY — nothing
     consumes these yet. Sizes and per-plate notes: assets/ui/MANIFEST.json. */
  --plate-desk-objects: url('../assets/ui/desk-objects-cut.webp');/*900x600 a*/
  --plate-ribbon-bookmark: url('../assets/ui/ribbon-bookmark-cut.webp');/*240x420 a*/
  --plate-index-tabs: url('../assets/ui/index-tabs-cut.webp');  /*  600x400 a */
  --plate-pencil: url('../assets/ui/pencil-cut.webp');          /*  700x160 a */
  --plate-note-slip: url('../assets/ui/note-slip-cut.webp');    /*  700x420 a */
  --plate-caption-strip: url('../assets/ui/caption-strip.webp');/* 1600x300  */
  --plate-book-fore-edge: url('../assets/ui/book-fore-edge-cut.webp');/*200x1000 a*/

  /* --- §4 RULE-LOCK: blank-paper twins (2026-08-31) ----------------------
     Owner ruling: runtime type must sit ON ruled lines, so the ruling becomes
     a CSS fact (a repeating-linear-gradient the engine can pitch, offset and
     turn off) instead of paint. These two plates are the SAME paper with the
     baked ruling erased — same canvas, same pixels, so every background-size
     / background-position crop written against the ruled plates above stays
     valid when swapped onto these. Everything else survives untouched: the
     pad's spiral and corner curl, the ledger's spine, worn edges, and BOTH
     dried-red margin rules (those are page furniture, not ruling).
     Congruent runtime pitches for the ruling engine, in SOURCE px:
       steno-pad     21 rules, pitch 25.93, first baseline y 112.4,
                     ruled box x140 y111 w625 h521 (divider was x452)
       ledger-spread 30 rules/page, pitch 29.52 (L) / 29.49 (R),
                     first baseline y 81.7, left box x40 y81 w755 h865,
                     right box x803 y80 w766 h864, red rules x168 / x1433
     Both baked pitches widen top-to-bottom with the photographed perspective
     (steno 24.8 -> 26.3, ledger 31.6 -> 29.5), so a uniform runtime pitch can
     only ever match the median — which is exactly why the paint had to go.
     DECLARED ONLY — nothing consumes these yet. Per-plate derivation, method
     and verification numbers: assets/ui/MANIFEST.json. */
  --plate-steno-blank: url('../assets/ui/steno-pad-blank.png');   /*  900x700 */
  --plate-ledger-blank: url('../assets/ui/ledger-spread-blank.webp');/*1600x1000*/

  /* desk-objects is a 3x2 grid of cut-outs on transparency: cells are 33.333%
     x 50%. Row 1 = watch open, watch closed, bell. Row 2 = bell muffled under
     a cloth, bail drawer-pull, EMPTY. background-size: 300% 200%.
     index-tabs is a 3x1 row: cells 33.333% x 100%, background-size: 300% 100%. */
  --desk-obj-cell-w: 33.3333%;
  --desk-obj-cell-h: 50%;
  --index-tab-cell-w: 33.3333%;
  --index-tab-cell-h: 100%;

  /* pin-sprites is a 5x2 grid of cut-outs on transparency: cells are 20% x
     50%. Row 1 = six brass pins (5 here, 6th at row 2 col 1); row 2 cols 2-5
     = four paperclips. background-size: 500% 200%. */
  --pin-cell-w: 20%;
  --pin-cell-h: 50%;

  /* --- §3 shadow: paper lift, never glow -------------------------------- */
  --pp-shadow-rest: 0 1px 2px rgba(0, 0, 0, 0.45);
  --pp-shadow-lift: 0 3px 7px rgba(0, 0, 0, 0.52);   /* 2–3px hover lift    */
  --pp-shadow-pinned: 0 2px 5px rgba(0, 0, 0, 0.50);
  --pp-lift-y: -2px;                                  /* the hover travel   */
  /* A heavy object resting ON the desk: a tight dark contact line under the
     near edge plus a wide soft falloff. Never baked into a plate — the book
     plate ships with its own scene shadow cropped away, so the grounding is a
     CSS fact and survives any re-lighting of the desk underneath. */
  --pp-shadow-contact:
    0 2px 3px rgba(0, 0, 0, 0.72),
    0 14px 26px -8px rgba(0, 0, 0, 0.78),
    0 34px 64px -20px rgba(0, 0, 0, 0.62);

  /* --- §3 motion: one reveal moment per screen -------------------------- */
  --pp-t-lift: 140ms;           /* hover/focus paper lift                   */
  --pp-t-settle: 320ms;         /* a card settling onto the board           */
  --pp-t-thread: 600ms;         /* the red thread drawing along the route   */
  --pp-t-stamp: 220ms;          /* the receipt stamp landing                */
  --pp-ease-paper: cubic-bezier(0.22, 0.61, 0.36, 1);
  --pp-ease-stamp: cubic-bezier(0.34, 1.32, 0.64, 1);
}

/* --------------------------------------------------------------------------
   Primitives. Deliberately few — the screens in R1b/R2 build on these.
   -------------------------------------------------------------------------- */

/* A painted plate: cover-fit, never stretched, never tinted by default. */
.paper-plate {
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  background-color: var(--pp-ink);
}

/* Runtime type ON paper. Two registers only. */
.paper-type {
  font-family: var(--font-type);
  letter-spacing: var(--track-type);
  color: var(--pp-type);
}
.paper-hand {
  font-family: var(--font-hand);
  color: var(--pp-graphite);
  font-size: 1.18em;            /* Caveat runs small for its point size     */
  line-height: 1.25;
}
.paper-stamp {
  font-family: var(--font-type);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--track-stamp);
  font-size: var(--fs-stamp);
  color: var(--pp-red);
}

/* Hover/focus is a paper lift: the object rises 2px and its shadow deepens.
   No glow, no outline swap, no colour change — §3. */
.paper-lift {
  box-shadow: var(--pp-shadow-rest);
  transform: translateY(0);
  transition: transform var(--pp-t-lift) var(--pp-ease-paper),
              box-shadow var(--pp-t-lift) var(--pp-ease-paper);
}
.paper-lift:hover,
.paper-lift:focus-visible {
  transform: translateY(var(--pp-lift-y));
  box-shadow: var(--pp-shadow-lift);
}

/* The graphite underline the SAY menu uses instead of a highlight. */
.paper-underline {
  background-image: linear-gradient(var(--pp-graphite), var(--pp-graphite));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1.5px;
  transition: background-size var(--pp-t-lift) var(--pp-ease-paper);
}
.paper-underline:hover,
.paper-underline:focus-visible,
.paper-underline[aria-selected='true'] {
  background-size: 100% 1.5px;
}

/* Optional rain overlay — §4 caps it at 20%. */
.rain-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--plate-rain-vignette) center / cover no-repeat;
  opacity: 0.18;
  mix-blend-mode: screen;
}

/* --------------------------------------------------------------------------
   Reduced motion. The lesson from the reduce-motion damage: nothing may gate
   state on an animation, so here motion is only ever removed — the hover lift
   collapses to a shadow change, and the thread/stamp reveals become instant
   (their JS still fires its completion callback on a timer).
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --pp-t-lift: 0ms;
    --pp-t-settle: 0ms;
    --pp-t-thread: 0ms;
    --pp-t-stamp: 0ms;
    --pp-lift-y: 0px;
  }
  .paper-lift,
  .paper-underline {
    transition: none;
  }
}
