/* ============================================================
   EngageDM — Paper substrate + physical-paper depth
   Loaded on EVERY page (public, dashboard, admin), directly after
   theme.css so it can refine that file's grounds without forking it.

   THE MATERIAL
   ------------
   The product is printed matter. Light is the default theme and it is
   warm bone stock, not white; dark is warm charcoal card stock, not a
   black screen. Russet is the ink on both. Everything follows from that:

   - .sheet uses a small radius, but the app-wide card mapping in section 7
     deliberately does NOT override each page's own radius — the paper cue
     is the cast shadow and the fibre, not the corner.
   - Depth is a CAST SHADOW from a light above and slightly in front,
     never a glow and never a coloured halo. A real sheet casts two
     shadows at once: a tight contact shadow at the edge where it meets
     the surface, and a wide soft ambient one. Using only the soft one
     is what makes CSS cards float like glass instead of lying flat.
   - Lifting a sheet SOFTENS the contact shadow and GROWS the ambient
     one. That relationship is the whole illusion — grow both equally
     and it reads as a scale transform, which is what it actually is.

   MOBILE FIRST
   ------------
   Every block here is authored phone-first: the base rules are the
   small-screen case and `min-width` queries add the larger ones. Tilt
   is gated behind `(hover: hover) and (pointer: fine)` so a touch
   device never pays for pointer maths it cannot trigger.

   JS CONTRACT (public/js/paper.js)
   --------------------------------
   [data-tilt] elements receive --tilt-x / --tilt-y / --tilt-lift.
============================================================ */

/* ============================================================
   1. STOCK
   Light is the default, so it is defined on bare :root. theme.css
   scopes its light palette to [data-theme="light"]; both are (0,1,0)
   and this file loads later, so these win where they overlap.
============================================================ */
:root {
  /* ── TEXTURE: TWO LAYERS, BECAUSE REAL STOCK HAS TWO ─────────────────
     A single fine-grain layer is what made the earlier version read as
     "slightly noisy flat colour" rather than as a material. Paper has a
     fine FIBRE at thread scale and a much coarser MOTTLE from how the
     pulp settled — several hundred pixels across. Layering both is what
     the eye reads as a surface; either alone reads as a filter.

     Both are inline SVG (no request) using fractalNoise (no tile seam).

     THE DESK AND A SHEET GET DIFFERENT AMOUNTS, and that split is the
     point. Grey noise over a pale ground reads as tone, so the same
     opacity that is barely felt across a large empty desk sits directly
     under 12px labels on a card, where the ui-ux-pro-max guidance is
     that texture starts costing legibility. The desk is a big empty
     surface and can take a lot; a sheet is a reading surface and takes
     roughly half. Dark sets both to the same value because a dark ground
     is LIGHTENED by grey noise and needs far less of it either way. */
  --paper-fibre: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.78' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23f)' opacity='0.32'/%3E%3C/svg%3E");
  --paper-fibre-sheet: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.78' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23f)' opacity='0.18'/%3E%3C/svg%3E");
  --paper-mottle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='620' height='620'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.012' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='620' height='620' filter='url(%23m)' opacity='0.22'/%3E%3C/svg%3E");
  /* ONE gradient doing both halves of the lighting: a soft highlight where
     the light lands, falling through the ground colour and into a warm
     edge shade. Two separate layers would be cleaner to read but would
     desynchronise the background-size / -repeat / -position lists on the
     body, which are positional and must stay the same length.

     This carries most of the "lit surface" cue on light. Without it a
     large pale area reads as a colour swatch no matter how much grain is
     on it — which is exactly what the light theme was doing. */
     The highlight is deliberately kept SHORT (spent by 32%) and modest.
     Cards do not carry the vignette, so a highlight that reaches as far
     down as the content lightens the desk past the sheets sitting on it
     and inverts the whole relationship — the desk ends up brighter than
     the paper on it, which reads as fog rather than as light. */
  --paper-vignette: radial-gradient(ellipse 132% 104% at 50% 6%,
                      rgba(255, 255, 255, 0.30) 0%,
                      rgba(255, 255, 255, 0)    32%,
                      rgba(92, 76, 50, 0.10)   100%);

  --paper-fibre-size:  200px;
  --paper-mottle-size: 620px;

  /* Shadow ink. Warm brown-grey — a neutral or cool shadow on warm stock
     is the fastest way to make paper look like plastic. Warmer and a
     little deeper than before, because the ground it falls on is now
     bone rather than near-white and a pale shadow simply vanished on it. */
  --paper-cast: 74, 61, 42;

  /* Two-part shadows: a tight CONTACT shadow where the sheet meets the
     desk, then a wide AMBIENT one. Both together are what reads as a
     sheet lying down; the ambient alone is what makes CSS cards float. */
  /* These are roughly DOUBLE what they were. On charcoal a shadow only has
     to be black to read; on bone it has to be dark enough to survive being
     laid on an already-warm ground, and the previous alphas (0.065–0.10)
     simply disappeared into it. Depth — not grain — is what was actually
     missing from the light theme: grain makes a surface look like a
     material, but only a cast shadow makes a card look like a SHEET. */
  --sheet-rest:
    0 0.5px 0.5px rgba(var(--paper-cast), 0.15),
    0 2px 4px     rgba(var(--paper-cast), 0.12),
    0 10px 22px -6px rgba(var(--paper-cast), 0.17);
  --sheet-lift:
    0 1px 2px   rgba(var(--paper-cast), 0.17),
    0 10px 20px rgba(var(--paper-cast), 0.15),
    0 30px 56px -14px rgba(var(--paper-cast), 0.27);
  --sheet-press:
    0 0.5px 1px rgba(var(--paper-cast), 0.17),
    inset 0 1px 3px rgba(var(--paper-cast), 0.13);

  /* The cut edge of a sheet, both halves of it. The top catches the light;
     the bottom is the thickness of the stock turning away from it.
     A white top inset ALONE does nothing here — the sheet is already
     #FDFCF7, so painting near-white on near-white was a no-op, and the
     bottom shade is doing all of the work. */
  --sheet-edge-light:
    inset 0  1px 0 rgba(255, 255, 255, 0.92),
    inset 0 -1px 0 rgba(var(--paper-cast), 0.07);

  --sheet-radius: 4px;
  --sheet-radius-lg: 8px;
}

/* Warm the light ground into stock. theme.css already removed the brand
   tint from the ground; this only adds warmth and paper whites.

   SCOPED TO [data-theme="light"], NOT BARE :root. theme.css uses bare
   :root for its DARK palette and scopes light to the attribute — so a
   surface colour declared on :root here would load later and win in
   BOTH themes, painting white sheets onto the dark ground with light
   text on them. Every page stamps an explicit data-theme before first
   paint, so the attribute selector always matches. */
[data-theme="light"] {
  /* WARM BONE. This has been tuned twice: first warm cream (too artisanal
     under a brown accent), then near-neutral (paper stopped reading as a
     material at all). Bone is the settled answer — it was the SERIF, not
     the ground, doing most of the artisanal work, and with a heavy
     geometric display face the ground can carry real warmth.

     The desk-to-sheet step (#F5F1E8 -> #FDFCF7) is deliberately wide. When
     they were a hair apart, cards had nothing to stand out FROM and the
     paper effect read as absent no matter how good the shadow was. */
  --bg:            #F5F1E8;   /* the desk */
  --bg-elevated:   #FDFCF7;   /* a sheet laid on it */
  --bg-elevated-2: #EFEADF;
  --bg-elevated-3: #FDFCF7;
  --bg-sunken:     #EDE8DC;   /* a recess */
  --bg-primary:    #F5F1E8;
  /* --bg-secondary is a STEP DOWN from the ground in dashboard.css and
     landing.css, not a sheet — keep the role, or every panel that uses it
     inverts. --bg-elevated / --bg-card-solid are the sheet tokens. */
  --bg-secondary:  #EFEADF;
  --bg-tertiary:   #E7E1D3;
  --bg-card-solid: #FDFCF7;
}

/* Charcoal card stock, lifted off theme.css's near-black screen ground:
   a dark sheet is still a sheet, so the desk sits above true black and a
   sheet laid on it a step lighter again. */
[data-theme="dark"] {
  /* Warm charcoal — enough warmth to read as stock rather than as a screen,
     but far enough from the accent's hue that russet stays legible ON it.
     Same widened desk-to-sheet step as the light theme. */
  --bg:            #141312;   /* the desk */
  --bg-elevated:   #1D1B18;   /* a sheet laid on it */
  --bg-elevated-2: #242220;
  --bg-elevated-3: #1D1B18;
  --bg-sunken:     #0E0D0C;   /* a recess */
  --bg-primary:    #141312;
  --bg-secondary:  #1A1917;   /* step down, not a sheet — see the light block */
  --bg-tertiary:   #242220;
  --bg-card-solid: #1D1B18;

  /* Grey noise LIGHTENS a dark ground, so an alpha that is invisible on
     bone is obvious on charcoal. Dark gets its own, weaker pair — but it
     still gets BOTH layers, because a dark sheet is still a sheet and the
     coarse mottle is most of what sells that. */
  --paper-fibre: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.86' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23f)' opacity='0.075'/%3E%3C/svg%3E");
  /* Same value as the desk, on purpose: the desk/sheet split exists because
     grey noise DARKENS a pale ground under text. On charcoal it lightens,
     and at 0.075 it is already below the level where it costs anything. */
  --paper-fibre-sheet: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.86' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23f)' opacity='0.075'/%3E%3C/svg%3E");
  --paper-mottle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='620' height='620'%3E%3Cfilter id='m'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.012' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='620' height='620' filter='url(%23m)' opacity='0.065'/%3E%3C/svg%3E");
  /* On charcoal the falloff has to DARKEN the edges, so the vignette is
     black rather than the light theme's warm brown. */
  --paper-vignette: radial-gradient(ellipse 130% 95% at 50% 18%,
                      transparent 44%, rgba(0, 0, 0, 0.34) 100%);

  --paper-cast: 0, 0, 0;
  --sheet-rest:
    0 0.5px 0.5px rgba(0, 0, 0, 0.42),
    0 2px 4px     rgba(0, 0, 0, 0.36),
    0 10px 22px -6px rgba(0, 0, 0, 0.48);
  --sheet-lift:
    0 1px 2px   rgba(0, 0, 0, 0.46),
    0 10px 22px rgba(0, 0, 0, 0.44),
    0 32px 64px -14px rgba(0, 0, 0, 0.64);
  --sheet-press:
    0 0.5px 1px rgba(0, 0, 0, 0.50),
    inset 0 1px 2px rgba(0, 0, 0, 0.44);
  /* On dark stock the lit cut is a warm white at low alpha, not pure white.
     Raised from 0.075 — it is the only thing separating a dark sheet's top
     edge from the dark desk behind it. */
  --sheet-edge-light: inset 0 1px 0 rgba(250, 246, 238, 0.10);
}

/* ============================================================
   2. THE GROUND
   Grain rides on the body background stack. A fixed pseudo-element
   overlay was the other option and was rejected: it creates a
   root-level stacking context, which is a long tail of z-index bugs
   across three separate apps for a texture.
============================================================ */
/* `html body`, not `body`. Every page-specific stylesheet loads after this
   one and several set their own `body` background; the element prefix is the
   one point of specificity needed to keep the grain. */
/* Layer order is top-down: vignette over fibre over mottle. The vignette
   goes on top so the edge falloff dims the texture with the ground rather
   than sitting under it, which is how a real lit surface behaves.

   `fixed` keeps the texture anchored while content scrolls — that is what
   makes it read as a surface the page sits ON, rather than a pattern that
   travels with the content. iOS Safari treats `fixed` as `scroll`, which
   is a graceful degradation, not a bug to work around. */
html body {
  background-color: var(--bg);
  background-image: var(--paper-vignette), var(--paper-fibre), var(--paper-mottle);
  background-size: cover,
                   var(--paper-fibre-size)  var(--paper-fibre-size),
                   var(--paper-mottle-size) var(--paper-mottle-size);
  background-repeat: no-repeat, repeat, repeat;
  background-attachment: fixed, fixed, fixed;
  background-position: center top, 0 0, 0 0;
}

/* Dark keeps theme.css's ambient brand wash; the texture layers go over it.
   Declared as ONE stack because background-image is a single property — a
   second rule would replace the wash rather than layer over it. Every
   comma-separated list below must keep the same five entries in the same
   order or the layers desynchronise. */
html[data-theme="dark"] body {
  background-image:
    var(--paper-vignette),
    var(--paper-fibre),
    var(--paper-mottle),
    radial-gradient(1100px 520px at 50% -8%, rgba(201, 121, 63, 0.05), transparent 72%),
    radial-gradient(900px 480px at 88% 4%, rgba(125, 211, 252, 0.022), transparent 70%);
  background-size: cover,
                   var(--paper-fibre-size)  var(--paper-fibre-size),
                   var(--paper-mottle-size) var(--paper-mottle-size),
                   auto, auto;
  background-repeat: no-repeat, repeat, repeat, no-repeat, no-repeat;
  background-attachment: fixed, fixed, fixed, fixed, fixed;
  background-position: center top, 0 0, 0 0, center top, center top;
}

/* The grain is decoration. At high contrast it is noise in the literal
   sense, so it goes. */
/* Texture is decoration. Someone asking for more contrast is asking for
   less of exactly this, so every layer goes — on the sheets too, not just
   the desk. `html` prefixes match the rules being undone. */
/* Killed at the TOKEN, not per selector. The card mapping in section 7 is a
   30-selector list and the sheen rules live in theme.css — an opt-out that
   has to name every consumer is one that silently misses the next one. */
@media (prefers-contrast: more) {
  :root, [data-theme="light"], [data-theme="dark"] {
    --paper-fibre: none;
    --paper-fibre-sheet: none;
    --paper-mottle: none;
    --paper-vignette: none;
  }
  /* The dark body also carries two ambient brand washes that are not in a
     variable, so its whole stack still has to be cleared by hand. */
  html[data-theme="dark"] body { background-image: none; }
}

/* ============================================================
   3. SHEET
   The one card primitive. Opt in with class="sheet".
============================================================ */
.sheet {
  position: relative;
  background-color: var(--bg-elevated);
  /* The sheet carries its OWN fibre. Without it a flat card sitting on a
     textured desk reads as pasted on — the texture stops at the card edge
     and the illusion goes with it. Fibre only, at SHEET weight: the coarse
     mottle is a property of a large surface and looks like a stain at card
     scale, the vignette belongs to the desk's lighting rather than to the
     sheet, and the desk's full-strength fibre sits too close under body
     text (see the two-weight note in section 1). */
  background-image: var(--paper-fibre-sheet);
  background-size: var(--paper-fibre-size) var(--paper-fibre-size);
  background-repeat: repeat;
  border: 1px solid var(--border-subtle);
  border-radius: var(--sheet-radius);
  box-shadow: var(--sheet-rest), var(--sheet-edge-light);
  transition:
    box-shadow 0.28s cubic-bezier(0.16, 1, 0.3, 1),
    transform  0.28s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Hover lift is desktop-only. On touch there is no hover state to enter —
   the styles would latch on tap and stay stuck until the next tap elsewhere. */
/* `translate`, not `transform`: a .sheet--lift is frequently also [data-tilt],
   and a transform here would replace the tilt's rotation rather than add to
   it. The independent property composes instead. */
@media (hover: hover) and (pointer: fine) {
  .sheet--lift:hover {
    box-shadow: var(--sheet-lift), var(--sheet-edge-light);
    translate: 0 -3px;
  }
}
.sheet--lift { transition: box-shadow 0.28s cubic-bezier(0.16,1,0.3,1), translate 0.28s cubic-bezier(0.16,1,0.3,1); }

/* A stack of sheets. Pseudo-elements rather than real nodes so any element
   can become a stack without markup changes. Rotations are deliberately
   under a degree — paper settles almost flat, and 3deg reads as a party
   invitation rather than a document. */
.sheet--stack::before,
.sheet--stack::after {
  content: '';
  position: absolute;
  inset: 0;
  border: 1px solid var(--border-subtle);
  border-radius: inherit;
  background: var(--bg-elevated);
  box-shadow: var(--sheet-rest);
  z-index: -1;
}
.sheet--stack::before { transform: rotate(-0.7deg) translate(-3px, 3px); }
.sheet--stack::after  { transform: rotate(0.55deg) translate(4px, 5px); opacity: 0.75; }

/* A turned-up corner. Drawn with a gradient rather than a clip so the fold
   catches light on one side and casts on the other, which is what makes it
   read as folded rather than cut. */
.sheet--fold { overflow: hidden; }
.sheet--fold::after {
  content: '';
  position: absolute;
  top: 0; right: 0;
  width: 26px; height: 26px;
  background:
    linear-gradient(225deg,
      var(--bg) 0%, var(--bg) 48%,
      rgba(var(--paper-cast), 0.14) 50%,
      var(--bg-elevated-2) 52%, var(--bg-elevated-2) 100%);
  border-bottom-left-radius: 3px;
  pointer-events: none;
}

/* ============================================================
   4. TILT
   Real 3D, driven by public/js/paper.js. The element rotates a couple of
   degrees toward the pointer and its shadow deepens with the lift, so
   the light source stays fixed while the sheet moves under it.

   Gated three ways: a fine pointer, no reduced-motion preference, and
   an explicit [data-tilt] opt-in. Anything unmatched keeps the flat
   sheet, which is a complete design on its own.
============================================================ */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  [data-tilt] {
    transform-style: preserve-3d;
    /* Long perspective. A short one exaggerates the rotation into a fisheye
       and the sheet reads as rubber. */
    transform:
      perspective(1100px)
      rotateX(var(--tilt-x, 0deg))
      rotateY(var(--tilt-y, 0deg))
      translateZ(var(--tilt-lift, 0px));
    transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s cubic-bezier(0.16, 1, 0.3, 1);
    will-change: transform;
  }
  /* While the pointer is inside, follow it immediately; the slow transition
     above is for the return to rest, which should settle rather than snap. */
  [data-tilt].is-tilting {
    transition: transform 0.08s linear, box-shadow 0.3s ease;
    box-shadow: var(--sheet-lift), var(--sheet-edge-light);
  }
  /* Content can be pushed off the sheet to sit above it in Z. */
  [data-tilt] .tilt-raise { transform: translateZ(28px); }
}

/* ============================================================
   5. TAPE + STAMP
   Two small physical details. Used sparingly — one per screen at most,
   or the page turns into a scrapbook.
============================================================ */
.tape {
  position: absolute;
  top: -9px; left: 50%;
  width: 92px; height: 22px;
  transform: translateX(-50%) rotate(-1.6deg);
  background: rgba(201, 121, 63, 0.16);
  border-left: 1px solid rgba(201, 121, 63, 0.22);
  border-right: 1px solid rgba(201, 121, 63, 0.22);
  pointer-events: none;
}

/* An inked rubber stamp. Slight rotation and a soft edge, because a stamp
   pressed by hand is never square and never solid. */
.stamp {
  display: inline-block;
  padding: 5px 12px;
  border: 2px solid currentColor;
  border-radius: 3px;
  color: var(--accent);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transform: rotate(-2.2deg);
  opacity: 0.88;
}

/* ============================================================
   6. RULES
   A printed rule, not a border: it fades at both ends the way a
   letterpress rule does where the plate lifts.
============================================================ */
.rule-fade {
  height: 1px;
  border: 0;
  background: linear-gradient(90deg,
    transparent, var(--border-strong) 12%, var(--border-strong) 88%, transparent);
}

/* ============================================================
   7. THE REST OF THE APP
   .sheet is opt-in and only the two rebuilt marketing pages use it, so
   the dashboard, admin panel and older public pages were getting the
   paper GROUND but none of the paper DEPTH — which is why the effect
   read as missing everywhere else.

   This maps the physics onto the card classes those pages already use,
   so no markup changes anywhere. Deliberately only the SHADOW and the
   radius cap: overriding their backgrounds and borders would fight each
   page's own design and is not what makes a surface read as paper — the
   two-part cast shadow is.

   Adding a card class? Add it here. The list is explicit rather than a
   [class*="card"] wildcard because that would also catch .admin-card-count,
   .ph-credit-card and every close button that happens to be inside one.
============================================================ */
/* PREFIXED WITH `html` ON PURPOSE. paper.css is injected straight after
   theme.css, which is correct for its tokens — but every page-specific
   stylesheet (dashboard.css, admin.css, landing.css…) loads AFTER it, so a
   plain `.admin-card` here loses to their own `.admin-card` at equal
   specificity. The element selector adds the one point needed to win, and
   is far less blunt than !important on a cross-cutting theme layer.

   Radius is deliberately NOT overridden. Each surface keeps the corner it
   was designed with — the paper cue is the two-part cast shadow, and
   forcing 8px corners across three apps would be a layout change dressed
   up as a texture change. */
html .section-card,
html .admin-card, html .admin-stat-card, html .admin-action-card,
html .admin-health-card, html .admin-plan-card, html .admin-dm-stat-card,
html .sys-auto-card, html .analytics-kpi-card, html .ov-card, html .at-card,
html .b-card, html .automation-card, html .template-card, html .builder-card,
html .settings-card, html .billing-pricing-card, html .upgrade-card-wrap,
html .slots-panel, html .success-card, html .no-account-card,
html .selected-post-card, html .pp-post-card, html .preview-panel,
html .docs-nav-card, html .feature-card, html .ia-card, html .auth-card,
html .stat-chip, html .stat-box, html .sup-tile,
/* Second sweep. These were declared in their own page stylesheets and had
   never been mapped, so they were the surfaces still reading as flat
   rectangles while the ones above read as sheets. Chips, filter pills and
   the landing page's `.demo-*` mockup internals are deliberately left out:
   a chip is too small for a cast shadow to read as anything but a smudge,
   and the demo internals sit INSIDE a sheet, where a second layer of fibre
   doubles the texture instead of extending it. */
html .metric-card, html .ct-stat-card, html .gw-card, html .ig-connect-card,
html .mc-post-card, html .ov-sidebar-card, html .partner-card,
html .partner-details-card, html .partner-funnel-card, html .partner-payout-card,
html .payout-card, html .earn-proj-card, html .pg-card, html .pro-gate-card,
html .prog-card, html .promo-create-card, html .settings-danger-card,
html .slots-card, html .tpl-card, html .uc-card, html .ud-card,
html .upgrade-card, html .pricing-card, html .auth-panel, html .manage-panel,
html .sw-panel, html .chart-box, html .coupon-box {
  box-shadow: var(--sheet-rest), var(--sheet-edge-light);
  /* Same fibre as .sheet. background-IMAGE only — never the shorthand —
     so each card keeps whatever background-color its own stylesheet set.
     The `html` prefix also wins over those stylesheets' `background:`
     shorthands, which would otherwise reset this back to none. */
  background-image: var(--paper-fibre-sheet);
  background-size: var(--paper-fibre-size) var(--paper-fibre-size);
  background-repeat: repeat;
}

/* A modal is a sheet held ABOVE the desk, so it gets the lifted shadow.
   The consent banner and the cookies-required wall are in here because they
   are the same thing: a sheet placed on top of the page, not part of it. */
html .modal-box, html .pp-modal-panel, html .pagr-modal-panel,
html .sp-modal-card, html .sp-wall-card {
  box-shadow: var(--sheet-lift), var(--sheet-edge-light);
  background-image: var(--paper-fibre-sheet);
  background-size: var(--paper-fibre-size) var(--paper-fibre-size);
  background-repeat: repeat;
}

/* Cards that are links or buttons lift on hover, like a sheet being picked
   up. Desktop only — on touch there is no hover to leave, so the style
   latches on tap and stays stuck. */
@media (hover: hover) and (pointer: fine) {
  a.section-card:hover, a.admin-action-card:hover, a.docs-nav-card:hover,
  a.automation-card:hover, a.template-card:hover, a.ov-card:hover,
  a.at-card:hover, a.pp-post-card:hover, a.feature-card:hover {
    box-shadow: var(--sheet-lift), var(--sheet-edge-light);
    translate: 0 -2px;
  }
}
a.section-card, a.admin-action-card, a.docs-nav-card, a.automation-card,
a.template-card, a.ov-card, a.at-card, a.pp-post-card, a.feature-card {
  transition: box-shadow 0.24s cubic-bezier(0.16,1,0.3,1), translate 0.24s cubic-bezier(0.16,1,0.3,1);
}

/* ============================================================
   8. TOUCH
   Applies everywhere, including dashboard and admin. 44px is the
   documented minimum; 8px of separation stops adjacent targets being
   one target in practice.
============================================================ */
@media (pointer: coarse) {
  .btn,
  button:not(.stepper-btn),
  .sheet a.lx-cta,
  [role="button"] { min-height: 44px; }

  .btn + .btn,
  [role="button"] + [role="button"] { margin-left: 8px; }
}
