/* Card playground — /testing/card-playground
 *
 * Two things live here: the harness chrome (controls, frame) and the card
 * THEMES themselves.
 *
 * How a theme works
 * -----------------
 * views/card.jsx sets two custom properties inline on each .card:
 *
 *     --card-face   the flat colour behind the art
 *     --card-art    url(...) of the card's picture, or unset
 *
 * and public/cards.css consumes them:
 *
 *     .card { background-color: var(--card-face, darksalmon);
 *             background-image: var(--card-art, none); }
 *
 * Because the component now only declares the *variables* inline and never
 * background-color / background-image, a rule here can simply set those two
 * properties and it wins — no !important needed. Re-pointing the variables
 * themselves also works, but has to be marked !important to beat the inline
 * declaration.
 *
 * Every theme is scoped to a .cardtheme-* class on the stage's <body>, so
 * nothing in this file can reach the real game.
 */

/* ── Harness chrome ─────────────────────────────────────────────────────── */
.card-playground-page {
  max-width: 1200px;
  margin: 16px auto;
  padding: 18px;
  /* The game's scenic background sits behind every page; controls have to read
     against it, so the harness gets its own opaque panel. */
  background: var(--cloud-bg, #14212e);
  color: var(--text, #f1faee);
  border-radius: 12px;
  box-shadow: 0 6px 24px #0006;
}

.cps-header h2 {
  margin: 0 0 6px;
}

.cps-header p {
  margin: 0 0 8px;
  opacity: 0.85;
  font-size: 0.9rem;
  line-height: 1.5;
}

.cps-note {
  border-left: 3px solid var(--cwl-accent, #c8960c);
  padding-left: 10px;
  opacity: 0.75 !important;
}

.cps-header code {
  background: rgba(127, 127, 127, 0.18);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 0.85em;
}

.cps-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: flex-start;
  margin: 16px 0;
  padding: 14px;
  border-radius: 10px;
  background: rgba(127, 127, 127, 0.12);
}

.cps-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 0.85rem;
  border: 0;
  margin: 0;
  padding: 0;
}

.cps-field > span,
.cps-field legend {
  font-weight: 600;
  opacity: 0.8;
  padding: 0;
}

.cps-field select {
  padding: 6px 8px;
  border-radius: 6px;
  min-width: 190px;
}

.cps-check {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 400;
  cursor: pointer;
}

.cps-viewport-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.cps-viewport-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: 6px 10px;
  border-radius: 6px;
  border: 1px solid rgba(127, 127, 127, 0.4);
  background: transparent;
  color: inherit;
  cursor: pointer;
  font: inherit;
  font-size: 0.82rem;
}

.cps-viewport-btn small {
  opacity: 0.6;
  font-size: 0.75em;
}

.cps-viewport-btn:hover,
.cps-viewport-btn.active {
  background: rgba(127, 127, 127, 0.22);
}

.cps-frame-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.82rem;
  opacity: 0.75;
  margin-bottom: 6px;
}

.cps-frame {
  border: 1px solid rgba(127, 127, 127, 0.45);
  border-radius: 8px;
  background: #11202f;
  max-width: 100%;
  display: block;
  /* Resized by cpsSetViewport; the transition makes a preset change readable
     rather than a jump. */
  transition: width 0.18s ease, height 0.18s ease;
}

/* ── The stage document itself ──────────────────────────────────────────── */
.card-playground-stage {
  margin: 0;
  min-height: 100vh;
  background: #11202f;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cps-stage {
  width: 100%;
  padding: 12px;
  box-sizing: border-box;
}

/* .hand is width:100% and .card-container is width:1px;flex-grow:1, so without
   a width on an ancestor every card collapses onto the same spot. */
.card-playground-stage .hands {
  width: 100%;
  max-width: 680px;
  margin: 0 auto;
}

.card-playground-stage .hand-container {
  width: 100%;
}

/* ── Themes ─────────────────────────────────────────────────────────────── */

/* Nothing overridden: the shipping card, for side-by-side comparison. */
.cardtheme-default .card {
  /* intentionally empty */
}

/* Art dropped, flat type colour, softer edges. */
.cardtheme-flat .card {
  background-image: none;
  border-width: 2px;
  border-radius: 10px;
  box-shadow: 0 2px 8px #0007;
}

.cardtheme-flat .card-name {
  text-shadow: none;
}

/* Aged paper: art knocked back behind a warm wash. */
.cardtheme-parchment .card {
  background-color: #e8d9b0;
  background-blend-mode: luminosity;
  border-color: #6b4f2a;
  border-radius: 6px;
  box-shadow: inset 0 0 24px #00000055, 0 3px 10px #0006;
}

/* The wash darkens unpredictably depending on the art underneath, so the name
   gets its own plaque rather than relying on contrast that may not be there —
   the sort of thing this playground exists to catch. */
.cardtheme-parchment .card-name {
  color: #2c1e0c;
  text-shadow: none;
  background: rgba(232, 217, 176, 0.92);
  border-radius: 3px;
  padding: 1px 4px;
  margin: 0 3px;
}

/* High-contrast dark with a coloured rim per type. */
.cardtheme-neon .card {
  background-color: #0d1117;
  background-blend-mode: overlay;
  border-radius: 12px;
  border-width: 2px;
}

.cardtheme-neon .card-type-offense { box-shadow: 0 0 12px #ff4d4d, inset 0 0 18px #ff4d4d33; }
.cardtheme-neon .card-type-magic { box-shadow: 0 0 12px #4dc3ff, inset 0 0 18px #4dc3ff33; }
.cardtheme-neon .card-type-defense { box-shadow: 0 0 12px #ffb84d, inset 0 0 18px #ffb84d33; }
.cardtheme-neon .card-type-special { box-shadow: 0 0 12px #b98cff, inset 0 0 18px #b98cff33; }
.cardtheme-neon .card-type-resource { box-shadow: 0 0 12px #6bffb0, inset 0 0 18px #6bffb033; }

/* Type colour only — the readability floor with no art to lean on. This one
   re-points the variable instead of the property, to show that route works
   too (it needs !important to beat the component's inline declaration). */
.cardtheme-noart .card {
  --card-art: none !important;
  /* Both sets have to go: the shipping rules read --card-art-v2 first. */
  --card-art-v2: none !important;
}

/* ── XL layout ─────────────────────────────────────────────────────────────
   A display-size card with rules text, arranged the way a printed TCG card is:
   art on top, the name as a title bar, the description in its own panel
   underneath. Composition is otherwise untouched — action top-left, cost
   middle-left, name below the art.

   This is the one place the chrome is allowed to scale. The in-game card is
   deliberately left at its fixed 16px/14px sizes; here the card is more than
   twice the size, so leaving them would make the values look like specks.

   Layout-scoped, not theme-scoped, so every theme can be viewed at XL. Rules
   here come after the themes in the file, so at equal specificity they win. */
.cps-xl .cps-stage {
  padding: 20px 12px;
}

.cps-xl .hands {
  max-width: 1040px;
}

.cps-xl .hand {
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  max-width: none;
  background: none;
}

.cps-xl .card-container {
  width: 232px;
  flex-grow: 0;
  flex-shrink: 0;
}

.cps-xl .card {
  width: 232px;
  /* Sized off the longest rules text in the deck rather than a guess: Curse is
     264 characters, and the next three (the Bribe cards) are ~235. At 13px in a
     ~205px column that is about eight lines, so the panel is 168px. Median card
     is 106 characters and uses less than half of it. */
  height: 470px;
}

.cps-xl .card-icon {
  width: 24px;
  height: 24px;
}

.cps-xl .card-value {
  font-size: 26px;
}

.cps-xl .card-top-left {
  top: 12px;
  left: 12px;
  gap: 5px;
}

.cps-xl .card-costs {
  /* Centred on the art rather than the whole card, now that the bottom third
     is a text panel. */
  top: 140px;
  left: 12px;
  gap: 8px;
}

.cps-xl .card-top-right {
  top: 12px;
  right: 12px;
  font-size: 18px;
}

/* Title bar: sits directly on top of the rules panel, like a card's type line. */
.cps-xl .card .card-name {
  left: 0;
  right: 0;
  bottom: 168px;
  top: auto;
  transform: none;
  max-width: none;
  font-size: 21px;
  padding: 5px 12px;
  border-radius: 0;
  text-align: center;
}

/* The rules panel. Aged paper so the text reads as printed rather than as an
   overlay floating on the art. */
.cps-xl .card-description {
  /* Opting in: card-themes.css hides the rules text everywhere by default,
     since most layouts have nowhere to put it. */
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 168px;
  box-sizing: border-box;
  padding: 11px 13px;
  /* Scrolls rather than clips if a description ever outgrows the panel — the
     two longest cards already sit close to the limit. */
  overflow: auto;
  background:
    linear-gradient(to bottom, rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0)) ,
    #efe4c8;
  color: #241c10;
  font-size: 13px;
  line-height: 1.4;
  text-align: left;
  text-shadow: none;
  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.35);
}

/* Themes that bury the nameplate off the bottom edge have to stop doing that
   here — at XL the name is a title bar with the rules panel beneath it, so
   there is nothing to hang off. */
.cps-xl .cardtheme-orb .card-name,
.cps-xl.cardtheme-orb .card .card-name {
  bottom: 168px;
  padding: 5px 12px;
  border-radius: 0;
  max-width: none;
}

/* Likewise the corner medallion scales up with everything else. */
.cps-xl.cardtheme-orb .card-top-left {
  top: 0;
  left: 0;
  min-width: 58px;
  min-height: 50px;
  padding: 7px 22px 11px 9px;
  border-radius: 0 0 42px 0;
}

.cps-xl.cardtheme-orb .card-cost {
  height: 42px;
  margin-left: -30px;
  padding: 0 16px 0 38px;
}

.cps-xl.cardtheme-engraved .card-name {
  padding: 5px 12px;
  background: none;
}

/* ── Reveal layout ─────────────────────────────────────────────────────────
   Title only, until you hover the title — then the rules text pulls up from
   behind it.

   The panel is parked below the card's bottom edge and clipped away by
   `overflow: hidden`; hovering translates it back to 0. It slides up *behind*
   the title bar (z-index) rather than across it, so the title reads as the
   drawer handle it is.

   The card is bigger than the in-game one because the panel has to be legible:
   at the shipping 100px width the longest description would run to twenty-odd
   lines. This is a browsing size, not a playing size.

   Hover only, so this is a desktop idea. A touch build would need the title to
   toggle a class instead — worth knowing before this goes anywhere near the
   real game. */
.cps-reveal .cps-stage {
  padding: 20px 12px;
}

.cps-reveal .hands {
  max-width: 1000px;
}

.cps-reveal .hand {
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  max-width: none;
  background: none;
}

.cps-reveal .card-container {
  width: 172px;
  flex-grow: 0;
  flex-shrink: 0;
}

.cps-reveal .card {
  width: 172px;
  height: 340px;
  overflow: hidden;
}

.cps-reveal .card-icon {
  width: 17px;
  height: 17px;
}

.cps-reveal .card-value {
  font-size: 18px;
}

.cps-reveal .card-top-left {
  top: 9px;
  left: 9px;
  gap: 4px;
}

.cps-reveal .card-costs {
  top: 44%;
  left: 9px;
  gap: 6px;
}

.cps-reveal .card-top-right {
  top: 9px;
  right: 9px;
  font-size: 14px;
}

/* The drawer handle. Full width along the bottom, above the panel in the
   stacking order so the text emerges from behind it. */
.cps-reveal .card .card-name {
  left: 0;
  right: 0;
  bottom: 0;
  top: auto;
  transform: none;
  max-width: none;
  height: 32px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 16px;
  padding: 0 10px;
  border-radius: 0;
  cursor: help;
  z-index: 2;
}

/* A caret so the title looks like it does something. Drawn with borders rather
   than a glyph so it needs no icon font. */
.cps-reveal .card .card-name::after {
  content: "";
  width: 0;
  height: 0;
  flex: none;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 5px solid currentColor;
  opacity: 0.5;
  transition: transform 0.24s ease, opacity 0.24s ease;
}

.cps-reveal .card-name:hover::after,
.cps-reveal .card-description:hover ~ .card-name::after {
  transform: rotate(180deg);
  opacity: 0.9;
}

.cps-reveal .card-description {
  /* Opting in: card-themes.css hides the rules text everywhere by default,
     since most layouts have nowhere to put it. */
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  /* Sits directly above the title bar when open. */
  bottom: 32px;
  height: 228px;
  box-sizing: border-box;
  padding: 11px 13px;
  overflow: auto;
  background: #efe4c8;
  color: #241c10;
  font-size: 12px;
  line-height: 1.42;
  text-align: left;
  text-shadow: none;
  z-index: 1;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.5);
  /* Parked entirely below the card: its own height plus the title bar it hides
     behind. */
  transform: translateY(calc(100% + 32px));
  transition: transform 0.26s cubic-bezier(0.22, 0.8, 0.3, 1);
}

/* What opens the drawer.
   
   Hover is the desktop path. Touch has no hover, so focus carries it: the card
   container already has tabindex="0", and a tap focuses it — which also means
   the drawer stays open afterwards instead of closing the moment the finger
   lifts, and keyboard users get it for free. :active covers the press itself so
   there is feedback before focus settles. Hovering the panel keeps it up so a
   long description can actually be read.
   
   All of it is gated on .cwl-help-on: card help being off means no card
   descriptions during play, and this is a card description. */
.cwl-help-on.cps-reveal .card-name:hover + .card-description,
.cwl-help-on.cps-reveal .card-description:hover,
.cwl-help-on.cps-reveal .card-container:focus-within .card-description,
.cwl-help-on.cps-reveal .card-container:active .card-description {
  transform: translateY(0);
}

/* With help off nothing opens, so the title should not advertise that it will.
   The panel keeps its parked position — hidden, not removed, so turning the
   setting back on needs no re-render. */
.cps-reveal:not(.cwl-help-on) .card .card-name::after {
  display: none;
}

.cps-reveal:not(.cwl-help-on) .card .card-name {
  cursor: default;
}

.cps-reveal:not(.cwl-help-on) .card-description {
  pointer-events: none;
}

/* The focus ring the game normally suppresses is worth having here: on touch
   it is the only cue that the tapped card is the open one. */
.cwl-help-on.cps-reveal .card-container:focus-within .card {
  outline: 2px solid rgba(255, 255, 255, 0.55);
  outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
  .cps-reveal .card-description,
  .cps-reveal .card .card-name::after {
    transition: none;
  }
}
