/* ==========================================================================
   DigitalProfile.lk — Templates gallery (templates.php)

   One idea runs through this file: every card is a small phone standing on a
   shelf, and the thing on its screen is the real template, loaded in an
   <iframe>. Everything else — the glow under the phone, the tilt on hover,
   the filter pills — exists to make that one idea read clearly.

   Contents
     1.  Gallery header
     2.  Filter pills
     3.  Grid
     4.  Card shell
     5.  Phone mock + the iframe inside it
     6.  Card body, badges and actions
     7.  Help strip
     8.  Live preview dialog
     9.  Responsive sizing
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. GALLERY HEADER
   -------------------------------------------------------------------------- */

.gallery-head {
  padding-block: calc(var(--space-section) * 0.82) var(--space-10);
  text-align: center;
}

.gallery-head__title {
  max-width: 18ch;
  margin-inline: auto;
  font-size: var(--text-h1);
  letter-spacing: var(--tracking-tight);
}

.gallery-head__lede {
  max-width: 56ch;
  margin: var(--space-5) auto 0;
  font-size: var(--text-lg);
  color: var(--color-text-muted);
}

/* Three plain numbers under the title. No cards, no borders — the phones
   below are the visual event and these should not compete with them. */
.gallery-stats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-5) var(--space-8);
  margin-block-start: var(--space-8);
  padding: 0;
  list-style: none;
}

.gallery-stats li {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 7rem;
}

.gallery-stats b {
  font-size: var(--text-h4);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
}

.gallery-stats span {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* Floating hairline that separates the header from the gallery. */
.gallery-head__rule {
  width: min(100%, 34rem);
  height: 1px;
  margin: var(--space-10) auto 0;
  background: var(--gradient-hairline);
}


/* --------------------------------------------------------------------------
   2. FILTER PILLS
   The bar sticks just under the site header so the filter stays reachable
   while scrolling a tall grid.
   -------------------------------------------------------------------------- */

.filterbar {
  position: sticky;
  top: var(--header-height);
  z-index: var(--z-sticky);
  display: flex;
  justify-content: center;
  padding-block: var(--space-4);
  margin-block-end: var(--space-10);
  /* No bar background: the glass pill is the only thing that shows, and the
     grid scrolls behind it. The strip itself must not swallow clicks. */
  pointer-events: none;
}

.filterbar .container { pointer-events: none; }

.filterbar__inner {
  pointer-events: auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  gap: var(--space-1);
  padding: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-surface-translucent);
  box-shadow: var(--shadow-sm);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.filterbar__btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-5);
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  white-space: nowrap;
  transition: color var(--duration-base) var(--ease-out),
              background-color var(--duration-base) var(--ease-out);
}

.filterbar__btn:hover { color: var(--color-text); }

.filterbar__btn[aria-pressed="true"] {
  color: var(--white);
  background: var(--gradient-button);
  box-shadow: var(--shadow-accent);
}

.filterbar__btn .icon { width: 1rem; height: 1rem; }

/* The count rides inside the pill and inverts with it. */
.filterbar__count {
  min-width: 1.35rem;
  padding-inline: var(--space-1);
  border-radius: var(--radius-full);
  background: var(--color-surface-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-subtle);
  text-align: center;
  transition: color var(--duration-base) var(--ease-out),
              background-color var(--duration-base) var(--ease-out);
}

.filterbar__btn[aria-pressed="true"] .filterbar__count {
  background: rgb(var(--rgb-white) / 0.22);
  color: var(--white);
}


/* --------------------------------------------------------------------------
   3. GRID
   1 column on phones, 2 on tablets, 3 on desktops. Sizes live in §9.
   -------------------------------------------------------------------------- */

.tpl-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-12) var(--space-8);
  /* Stretched, not start-aligned: cards in a row match height, so the pair of
     buttons lines up across the row however long each blurb runs. */
  align-items: stretch;
}

/* Replayed by the filter script so a tier change feels like a deal of cards. */
@keyframes card-in {
  from { opacity: 0; transform: translateY(18px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}

.js .tpl.is-entering {
  animation: card-in var(--duration-slow) var(--ease-out) backwards;
  animation-delay: var(--card-delay, 0ms);
}

/* Nothing matched — only ever shown by the script. */
.tpl-empty {
  grid-column: 1 / -1;
  padding: var(--space-12) var(--space-6);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-xl);
  text-align: center;
  color: var(--color-text-muted);
}


/* --------------------------------------------------------------------------
   4. CARD SHELL
   -------------------------------------------------------------------------- */

.tpl {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* An author `display` beats the browser's own [hidden] rule, so filtered-out
   cards need this line to actually leave the grid. */
.tpl[hidden] { display: none; }

/* The stage is the shelf the phone stands on: a soft pedestal of light,
   a floor shadow, and the phone itself lifting a few pixels on hover. */
.tpl__stage {
  position: relative;
  display: flex;
  justify-content: center;
  padding-block: var(--space-6);
  border-radius: var(--radius-2xl);
  isolation: isolate;
}

.tpl__stage::before {
  content: "";
  position: absolute;
  inset: 12% 6% 6%;
  z-index: -1;
  border-radius: var(--radius-3xl);
  background: var(--gradient-accent-soft);
  opacity: 0;
  filter: blur(26px);
  transform: scale(0.92);
  transition: opacity var(--duration-slow) var(--ease-out),
              transform var(--duration-slow) var(--ease-out);
}

.tpl:hover .tpl__stage::before,
.tpl:focus-within .tpl__stage::before {
  opacity: 1;
  transform: scale(1);
}

/* Floor shadow — an ellipse under the phone, not a box shadow, so the phone
   reads as an object standing in space rather than a rectangle on a page. */
.tpl__shadow {
  position: absolute;
  bottom: var(--space-3);
  left: 50%;
  z-index: -1;
  width: 62%;
  height: var(--space-5);
  border-radius: 50%;
  background: rgb(var(--rgb-slate-900) / 0.26);
  filter: blur(14px);
  transform: translateX(-50%) scaleX(1);
  transition: opacity var(--duration-slow) var(--ease-out),
              transform var(--duration-slow) var(--ease-out);
}

.tpl:hover .tpl__shadow,
.tpl:focus-within .tpl__shadow {
  opacity: 0.7;
  transform: translateX(-50%) scaleX(1.12) translateY(var(--space-2));
}


/* --------------------------------------------------------------------------
   5. PHONE MOCK
   The device is three nested rounded rectangles — body, rim highlight,
   screen — plus the side buttons and a screen-edge inner shadow. The real
   template is an <iframe> laid out at a virtual phone width (--vw) and then
   scaled down to the screen width (--screen-w), so the embedded page runs
   its genuine mobile layout instead of a squashed desktop one.
   -------------------------------------------------------------------------- */

.phone-mock {
  --vw: 390;          /* virtual viewport the template lays out at, in px   */
  --screen-w: 262;    /* painted screen width, in px                        */
  --screen-ar: 2.08;  /* screen height / screen width                       */
  --peek: 240;        /* extra page height revealed on hover, in virtual px */
  --scale: calc(var(--screen-w) / var(--vw));
  --bezel: var(--space-2);

  position: relative;
  padding: var(--bezel);
  /* Outer radius = glass radius + bezel, so the two curves stay concentric. */
  border-radius: calc(var(--radius-3xl) + var(--bezel));
  background:
    linear-gradient(150deg, var(--slate-600) 0%, var(--slate-900) 34%,
                            var(--slate-800) 62%, var(--slate-950) 100%);
  box-shadow: var(--shadow-float);
  transition: transform var(--duration-slow) var(--ease-spring);
}

.tpl:hover .phone-mock,
.tpl:focus-within .phone-mock {
  transform: translateY(calc(var(--space-2) * -1));
}

/* Hairline rim — the glint along the polished metal edge. */
.phone-mock::after {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid rgb(var(--rgb-white) / 0.16);
  border-radius: inherit;
  pointer-events: none;
}

/* Side buttons. Decorative, drawn as thin slivers on the device edge. */
/* Positioned in percentages of the device height so the buttons keep their
   proportions at every screen size in §9. */
.phone-mock__key {
  position: absolute;
  left: calc(var(--space-1) * -0.5);
  width: calc(var(--space-1) * 0.5);
  border-radius: var(--radius-full);
  background: linear-gradient(to right, var(--slate-950), var(--slate-600));
}

.phone-mock__key--mute { top: 15%; height: 3.4%; }
.phone-mock__key--up   { top: 21.5%; height: 7%; }
.phone-mock__key--down { top: 30%; height: 7%; }

.phone-mock__key--power {
  top: 23.5%;
  left: auto;
  right: calc(var(--space-1) * -0.5);
  height: 10%;
  background: linear-gradient(to left, var(--slate-950), var(--slate-600));
}

.phone-mock__screen {
  position: relative;
  width: calc(var(--screen-w) * 1px);
  height: calc(var(--screen-w) * var(--screen-ar) * 1px);
  border-radius: var(--radius-3xl);
  background: var(--white);
  overflow: hidden;
  isolation: isolate;
}

/* Inner shadow where the glass meets the bezel. */
.phone-mock__screen::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--z-raised);
  border-radius: inherit;
  box-shadow: inset 0 0 0 1px rgb(var(--rgb-slate-900) / 0.14),
              inset 0 var(--space-1) var(--space-2) rgb(var(--rgb-slate-900) / 0.18);
  pointer-events: none;
}

/* Pill camera cut-out and home indicator. */
.phone-mock__island,
.phone-mock__home {
  position: absolute;
  left: 50%;
  z-index: var(--z-raised);
  border-radius: var(--radius-full);
  transform: translateX(-50%);
  pointer-events: none;
}

/* An earpiece slit rather than a camera island: the template behind it starts
   at the very top of the glass, and a full island would sit on its first line
   of text. Multiply keeps it off dark pages entirely. */
.phone-mock__island {
  top: var(--space-1);
  width: var(--space-16);
  height: calc(var(--space-1) * 0.9);
  background: rgb(var(--rgb-slate-900) / 0.4);
  mix-blend-mode: multiply;
}

.phone-mock__home {
  bottom: var(--space-2);
  width: 36%;
  height: var(--space-1);
  background: rgb(var(--rgb-slate-900) / 0.4);
  mix-blend-mode: multiply;
}

/* The poster sits on top of the iframe and fades out once the frame has
   painted. It is also the whole picture when scripting or framing fails. */
.phone-mock__poster {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity var(--duration-slower) var(--ease-out);
}

.tpl.is-live .phone-mock__poster {
  opacity: 0;
  pointer-events: none;
}

/* The template itself. Thumbnails are display-only: no pointer events, no
   tab stop, no scrollbars. Interaction happens in the preview dialog. */
.phone-mock__doc {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  display: block;
  width: calc(var(--vw) * 1px);
  height: calc((var(--vw) * var(--screen-ar) + var(--peek)) * 1px);
  border: 0;
  background: var(--white);
  transform-origin: 0 0;
  transform: scale(var(--scale));
  /* Deliberately slower than any UI transition: this is a page being walked
     through, not a control responding. */
  transition: transform calc(var(--duration-slower) * 2) var(--ease-out);
}

.tpl .phone-mock__doc { pointer-events: none; }

/* Hovering walks the page down by --peek virtual pixels — the translate
   happens in the iframe's own coordinate space, before the scale. */
.tpl:hover .phone-mock__doc,
.tpl:focus-within .phone-mock__doc {
  transform: scale(var(--scale)) translateY(calc(var(--peek) * -1px));
}

/* Blurred glass chip over the screen inviting the full preview. */
.tpl__hover {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-items: end center;
  padding-block-end: var(--space-8);
  border-radius: inherit;
  /* Weighted to the bottom so the part of the page that hover just revealed
     stays readable while the chip still has something to sit against. */
  background: linear-gradient(to top,
              rgb(var(--rgb-slate-900) / 0.62),
              rgb(var(--rgb-slate-900) / 0.12) 55%,
              transparent);
  opacity: 0;
  backdrop-filter: blur(1.5px);
  -webkit-backdrop-filter: blur(1.5px);
  transition: opacity var(--duration-base) var(--ease-out);
}

.tpl:hover .tpl__hover,
.tpl:focus-within .tpl__hover { opacity: 1; }

.tpl__hover-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  border: 1px solid rgb(var(--rgb-white) / 0.28);
  border-radius: var(--radius-full);
  background: rgb(var(--rgb-white) / 0.9);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--slate-900);
  transform: translateY(var(--space-2)) scale(0.96);
  transition: transform var(--duration-base) var(--ease-spring);
}

.tpl:hover .tpl__hover-chip,
.tpl:focus-within .tpl__hover-chip { transform: none; }

.tpl__hover-chip .icon { width: 1rem; height: 1rem; color: var(--blue-600); }


/* --------------------------------------------------------------------------
   6. CARD BODY
   -------------------------------------------------------------------------- */

.tpl__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-3);
  padding-inline: var(--space-1);
  text-align: center;
}

.tpl__heading {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2) var(--space-3);
}

.tpl__name {
  font-size: var(--text-h5);
  letter-spacing: var(--tracking-tight);
}

/* Tier pill. Basic is quiet, Standard carries the accent, Premium is the
   full gradient — the badge alone should tell you where you are. */
.tier {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
}

.tier--basic {
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface-muted);
  color: var(--color-text-muted);
}

.tier--standard {
  border: 1px solid var(--color-accent-soft-border);
  background: var(--color-accent-soft);
  color: var(--color-accent-text);
}

.tier--premium {
  border: 1px solid transparent;
  background: var(--gradient-accent);
  color: var(--white);
  box-shadow: var(--shadow-accent);
}

.tpl__blurb {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.tpl__tags {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin: var(--space-1) 0 0;
  padding: 0;
  list-style: none;
}

.tpl__tags li {
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-surface);
  font-size: var(--text-xs);
  color: var(--color-text-subtle);
}

.tpl__actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
  margin-block-start: auto;
  padding-block-start: var(--space-4);
}

.tpl__actions .btn { width: 100%; }


/* --------------------------------------------------------------------------
   7. HELP STRIP
   -------------------------------------------------------------------------- */

.tpl-help {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-3) var(--space-6);
  margin-block-start: var(--space-16);
  padding: var(--space-6) var(--space-8);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
  text-align: center;
}

.tpl-help p { color: var(--color-text-muted); }
.tpl-help strong { color: var(--color-text); }


/* --------------------------------------------------------------------------
   8. LIVE PREVIEW DIALOG
   Here the iframe is life-size and fully interactive — same page, same
   phone frame, nothing scaled.
   -------------------------------------------------------------------------- */

/* The dialog fills the viewport and the panel is centred inside it with auto
   margins, so a panel taller than the window overflows downward and scrolls
   instead of having its head cut off. Filling the viewport also means any
   click outside the panel lands on the dialog itself — that is the backdrop
   click the script listens for. */
.preview {
  inset: 0;
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--color-text);
  overflow: auto;
  overscroll-behavior: contain;
}

.preview[open] { display: grid; }

.preview::backdrop {
  background: rgb(var(--rgb-slate-900) / 0.62);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.preview__panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  align-items: center;
  width: min(30rem, 100%);
  margin: auto;
  padding: var(--space-5);
}

.preview__head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  width: 100%;
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface-translucent);
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  text-align: left;
}

.preview__title { font-size: var(--text-h5); }

.preview__sub {
  margin-block-start: var(--space-1);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.preview__close {
  display: grid;
  flex-shrink: 0;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  margin-inline-start: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text-muted);
  transition: color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}

.preview__close:hover {
  color: var(--color-text);
  border-color: var(--color-border-strong);
}

.preview__close .icon { width: 1.1rem; height: 1.1rem; }

/* Life-size: the screen width *is* the viewport the template lays out at,
   so no scaling is involved and scrolling is the page's own. */
.preview .phone-mock__screen {
  width: min(24.375rem, 84vw);
  height: min(44rem, 62vh);
}

.preview .phone-mock__doc {
  position: static;
  width: 100%;
  height: 100%;
  transform: none;
}

.preview__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  width: 100%;
}


/* --------------------------------------------------------------------------
   9. RESPONSIVE SIZING
   The phone is drawn at real pixel sizes, so each breakpoint picks a screen
   width that leaves the card comfortable at that column count.
   -------------------------------------------------------------------------- */

/* Four pills will not sit in one row on a phone, and a ragged wrap looks like
   an accident — so below the two-column breakpoint they become a tidy 2 x 2. */
@media (max-width: 39.99rem) {
  .filterbar__inner {
    display: grid;
    grid-template-columns: 1fr 1fr;
    width: min(22rem, 100%);
    border-radius: var(--radius-xl);
  }

  .filterbar__btn { justify-content: center; }
}

@media (max-width: 23.4375rem) {       /* 375px — small phones */
  .tpl-grid .phone-mock { --screen-w: 228; }
  .tpl__actions { grid-template-columns: 1fr; }
}

@media (min-width: 40rem) {            /* 640px — two columns */
  .tpl-grid { grid-template-columns: repeat(2, 1fr); }
  .tpl-grid .phone-mock { --screen-w: 232; }
}

@media (min-width: 52rem) {            /* 832px — roomier two columns */
  .tpl-grid .phone-mock { --screen-w: 268; }
}

@media (min-width: 64rem) {            /* 1024px — three columns */
  .tpl-grid { grid-template-columns: repeat(3, 1fr); }
  .tpl-grid .phone-mock { --screen-w: 238; }
}

@media (min-width: 75rem) {            /* 1200px */
  .tpl-grid { gap: var(--space-16) var(--space-10); }
  .tpl-grid .phone-mock { --screen-w: 270; }
}

/* Pointer-less devices never see hover, so give them the resting state and
   skip the work of animating a transform that will not be triggered. */
@media (hover: none) {
  .tpl__hover { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .phone-mock,
  .phone-mock__doc,
  .tpl__shadow,
  .tpl__stage::before,
  .tpl__hover-chip { transition-duration: 1ms; }

  .js .tpl.is-entering { animation: none; }

  .tpl:hover .phone-mock__doc,
  .tpl:focus-within .phone-mock__doc { transform: scale(var(--scale)); }
}
