/* ===========================================================================
   library.css — the project cards, and the panel they become
   ---------------------------------------------------------------------------
   Loaded alongside game.css, which already owns the room: the fixed root, the
   canvas, the door hit boxes, the sign plates and the fallback link list. This
   file adds the one thing the projects page has and the village does not -- a
   panel -- and it does it the same way: two layouts, switched by .is-ready.

     (no class)   an ordinary section of six project cards in a grid, below the
                  list of links that jump to them. This is the served page.
     .is-ready    the grid becomes a panel down the right-hand edge, every card
                  is hidden, and .is-open picks the one showing.

   The cards are identical markup in both. Nothing is duplicated, so there is no
   second copy of the writing to keep in sync -- see panel.js.
   =========================================================================== */

/* ===== FALLBACK: an ordinary page ======================================== */

.panel {
  width: 100%;
  max-width: 64rem;
}

/* Only ever useful once the panel is a panel. */
.panel__close { display: none; }

.projects-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: 1.25rem;
}

.project-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 4px solid var(--emerald);
  border-radius: 8px;
  padding: 1.5rem;
}

.project-card h3 {
  font-family: var(--font-display);
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  margin: 0.75rem 0 0.6rem;
  color: var(--text);
}

.project-card p {
  color: var(--muted);
  line-height: 1.7;
  font-size: 0.94rem;
}

/* game.css zeroes every margin, so a card with more than one paragraph needs
   the gap put back or the prose runs together. Only the written cards have a
   second paragraph; the placeholders are one each. */
.project-card p + p {
  margin-top: 0.75rem;
}

.project-badge {
  display: inline-block;
  padding: 0.3rem 0.6rem;
  border-radius: 999px;
  background: rgba(217, 164, 65, 0.15);
  color: var(--accent);
  font-family: var(--font-display);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.project-tech {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 1rem;
}

/* --card, not --card2. Dry grass on raised moss measures 4.52:1 -- over the
   line, but with nothing left for a future tweak to spend. The darker chip is
   5.1:1 and still reads as raised against the panel's gradient. Lightness
   only; the hue is the theme's. */
.tech-tag {
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--card);
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 0.75rem;
}

.project-link {
  display: inline-block;
  margin-top: 1.1rem;
  color: var(--accent);
  font-family: var(--font-display);
  font-size: 0.8rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
}

.project-link::after { content: " \2192"; }

/* Placeholders go nowhere. Dimming them is honest; leaving the link live would
   promise a page that does not exist. */
.project-card.placeholder .project-link {
  color: var(--muted);
  pointer-events: none;
}

/* ===== READY: the panel ==================================================
   Sits above the door overlay (z-index 2) and the plaque (3); game.css's
   stacking context on #game keeps the whole lot below the nav regardless.
   ======================================================================== */

.game.is-ready .panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 4;
  width: min(30rem, 92vw);
  max-width: none;
  padding: 4.5rem 1.5rem calc(2rem + env(safe-area-inset-bottom));
  overflow-y: auto;
  overscroll-behavior: contain;
  background: linear-gradient(180deg, var(--bg), var(--bg-deep));
  border-left: 2px solid var(--line);
  box-shadow: -12px 0 32px rgba(15, 23, 13, 0.5);

  /* CLOSED. All three matter and none is redundant:

     transform      slides it off the right edge
     visibility     takes it out of the tab order and out of hit testing. A
                    panel that is merely translated is still focusable and
                    still a full-height sheet over the play area -- which is
                    how tap-to-move died the first time a full-area overlay was
                    added to this game. panel.js sets `inert` as well; this is
                    the half that works in engines without it.
     pointer-events belt and braces for the closing animation, during which
                    visibility is still `visible`.

     NOTE THE ABSENCE OF A TRANSITION HERE. That is the whole point.

     These three properties are the CLOSED STATE, and a state you can only
     reach by animating into it is not a state -- it is a hope. When .is-ready
     lands, transform and visibility both change (none -> translateX, visible
     -> hidden), so a transition declared here would animate the panel out on
     every single page load, and if the animation timeline is not running the
     panel never arrives: a full-height sheet of project cards, links in the
     tab order, sitting over the room. That was observed, not theorised.
     panel.js arms the transition a couple of frames later instead, so the
     closed state is reached statically and the animation is decoration. If the
     arming never happens, the panel simply opens and closes instantly. */
  transform: translateX(100%);
  visibility: hidden;
  pointer-events: none;
}

/* Added by panel.js once the closed state above has actually been painted. */
.game.is-ready .panel.is-armed {
  transition: transform 0.28s ease, visibility 0s linear 0.28s;
}

.game.is-ready .panel.is-open {
  transform: none;
  visibility: visible;
  pointer-events: auto;
}

.game.is-ready .panel.is-armed.is-open {
  transition: transform 0.28s ease, visibility 0s linear 0s;
}

.game.is-ready .projects-grid {
  display: block;
}

.game.is-ready .project-card {
  display: none;
  border-left-width: 4px;
  padding: 1.25rem 0 0;
  background: none;
  border: 0;
  border-radius: 0;
}

.game.is-ready .project-card.is-open {
  display: block;
}

/* The card takes focus when it opens (panel.js), so it needs a focus ring that
   reads as "here is the thing you just opened" rather than a stray outline. */
.game.is-ready .project-card:focus {
  outline: none;
}

.game.is-ready .project-card:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 6px;
  border-radius: 6px;
}

.game.is-ready .project-card h3 {
  font-size: 1.5rem;
  line-height: 1.3;
}

.game.is-ready .project-card p {
  font-size: 1rem;
}

.game.is-ready .panel__close {
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  top: 4.2rem;
  right: 1.25rem;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--card);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease;
}

.game.is-ready .panel__close:hover {
  background: var(--card2);
  border-color: var(--accent);
}

.game.is-ready .panel__close:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* ===== SIGN PLATES HANG BELOW HERE, NOT ABOVE ============================
   game.css hangs a plate above its hit box, which is right in the village:
   the plate reads as a shop sign over a door, and every village door is on
   row 10 or lower so it is never near the top of the screen.

   This room cannot do that. Four of its six pieces stand against the TOP wall,
   the camera clamps at the top of the map, and the nav header is fixed over
   that exact strip -- so a plate hung above a bookcase competes for the same
   pixels as the hamburger. On a landscape phone (812x375) five plates landed
   at y=61 with the header bottom at y=76: behind it.

   Raising the wall does not fix it. The camera follows the player, so adding
   rows above the shelves moves the player down by the same amount and the
   plates land in exactly the same place on screen. The gap that matters is
   between the player and the plate, not between the plate and row 0.

   So hang them underneath. For furniture you walk up to and read from the
   front, a label between you and the piece is if anything the more natural
   place for it, and it removes the whole class of collision rather than
   tuning around it. Nothing here is near the bottom of the map, so there is
   no symmetric problem with the plaque.
   ======================================================================== */

.game.is-ready .door > span {
  bottom: auto;
  top: calc(100% + 3px);
}

/* Hanging them below introduces one collision at the other end: the globe and
   the table sit low enough that their plates can reach the credit plaque when
   the camera is near the top of the room. The plaque is decoration -- a
   translucent gradient with pointer-events:none -- and a label naming what you
   are standing at is not, so the plaque gives way. game.css puts it at
   z-index 3, above the door overlay at 2; dropping it to 1 leaves it above the
   vignette and below the plates. The panel at 4 is unaffected. */
.game.is-ready .game__note {
  z-index: 1;
}

/* The way out is not a project. Give its plate the canopy green so it reads as
   a different kind of thing from the six amber ones. */
.door--exit { border-left-color: var(--accent); }

.game.is-ready .door--exit > span {
  border-color: var(--emerald);
  color: var(--emerald);
}

.game.is-ready .door--exit.is-near > span {
  border-color: var(--emerald);
  background: var(--emerald);
  color: var(--bg-deep);
}

/* ===== MOTION ============================================================ */

@media (prefers-reduced-motion: reduce) {
  .game.is-ready .panel.is-armed,
  .game.is-ready .panel.is-armed.is-open {
    transition: none;
  }
  .game.is-ready .panel__close { transition: none; }
}
