/* --frame-vh: the REAL device viewport height, captured once when this page is
   embedded in an iframe that sizes itself to our content. Without it, 100dvh
   inside the frame resolves to the frame's own height, so growing the frame
   grows the content, which grows the frame - an infinite loop. Falls back to
   100dvh when not framed. */
:root {
  --parchment: #edede8;
  --card: #f6f5f0;
  --ink: #182743;
  --ink-soft: #4a5670;
  --ink-faint: #8b93a6;
  --line: #d8d6cc;
  --good: #1a7f4e;
  --warm: #b4552d;
  --frame-hi: #fdfcf8;
  --frame-lo: #e7e4d7;
  --frame-edge: #d6d2c4;
  /* Strata sets its endgame actions and archive chips in Space Mono, which
     reaches that page through a next/font CSS var. This document is static
     and outside the Next bundle, so it cannot see that var and there is no
     stable URL for the hashed woff2 - the system mono stack is the closest
     match that costs no request and cannot 404. */
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--parchment);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.site {
  min-height: var(--frame-vh, 100dvh);
  display: flex;
  flex-direction: column;
  padding: 0 16px calc(24px + env(safe-area-inset-bottom));
}

/* Top bar: matches NavBar.tsx (text-lg 600 tracking-.18em wordmark,
   muted More Games + profile icon, sticky, no divider) */
.topbar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--parchment);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  min-height: 44px;
  padding: 8px 16px;
  margin: 0 -16px;
}

@media (min-width: 1240px) {
  .topbar { padding: 8px 16px; margin: 0 -28px; }
}

.more-games {
  justify-self: start;
  font-size: 14px;
  font-weight: 600;
  color: #47566c;
  text-decoration: none;
  white-space: nowrap;
  padding: 8px 8px 8px 0;
}

.more-games:hover { color: #162130; }

.wordmark {
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-indent: 0.18em;
  text-transform: uppercase;
  color: #162130;
}

/* Archive and other sub-pages keep the wordmark and hang the section name
   under it, the way NavBar does on the React games. */
.wordmark-sub {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  color: var(--ink-faint);
}

.account {
  justify-self: end;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  color: #47566c;
}

.account:hover { color: #162130; }

/* Layout: left games rail, window center, guess panel right */
.layout {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Fill the first viewport so the how-to article stays below the fold,
     like the live game pages. */
  min-height: calc(var(--frame-vh, 100dvh) - 130px);
  /* Centre the window and guess box in that space. Left top-aligned, the
     leftover height piled up underneath the guess box, which both looked like
     a gap and pulled the article up into the same screen. */
  justify-content: center;
}

/* Left rail: plain list, name + blurb + hairline, like the live site */
.rail { display: none; }


.rail-item {
  display: block;
  text-decoration: none;
  padding: 11px 0 12px;
  border-bottom: 1px solid var(--line);
}

.rail-item:last-child { border-bottom: none; }

.rail-title {
  display: block;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
}

.rail-blurb {
  display: block;
  margin-top: 2px;
  font-size: 12.5px;
  color: var(--ink-soft);
}

/* Cabin window */
.window-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 8px;
  width: fit-content;
  margin: 0 auto;
}

.porthole {
  position: relative;
  /* The glass takes the whole gesture, in both axes.

     This was pan-y, to leave vertical swipes to the page. The cost was that
     looking UP or DOWN was impossible on a phone: the browser routed those
     drags to the scroller and the pointermove handler never ran, so half the
     window was unreachable on the devices that need leaning most.

     The trade-off is deliberate: a thumb that lands on the window looks
     around instead of scrolling. Everything outside the frame - the header,
     the guess row and the slack above and below it - still scrolls normally,
     and the porthole is a little over half the screen height, so there is
     always somewhere to start a scroll from. */
  touch-action: none;
  width: min(92vw, 430px);
  height: min(116vw, 540px);
  border-radius: 88px;
  background: linear-gradient(168deg, var(--frame-hi) 0%, #f3f1e8 55%, var(--frame-lo) 100%);
  padding: 20px;
  box-shadow:
    0 1px 2px rgba(24, 39, 67, 0.10),
    0 18px 44px rgba(24, 39, 67, 0.16),
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    inset 0 0 0 1px var(--frame-edge);
}

/* Round over: the window stops looking around, so it must stop swallowing the
   gesture too, or a thumb on the glass would do nothing at all and the endcard
   below it would be unscrollable from more than half the screen. */
.is-over .porthole { touch-action: pan-y; }

/* The opening: this is what you actually see through. */
.porthole .aperture {
  position: absolute;
  inset: 20px;
  border-radius: 70px;
  overflow: hidden;
  background: #b6c6cf;
  transform: translateZ(0);
}

/* The map is rendered well beyond the opening so leaning shifts which slice
   shows, the way a real window works. Deliberately generous: the zoom is set
   from the opening, so what you see at rest is the intended view and leaning
   genuinely reaches past it in every direction.

   MUST stay comfortably larger than LEAN in main.js, or leaning to a corner
   drags the rendered edge into the opening. At LEAN 0.18 this leaves 8% of
   the opening as margin on every side. */
.porthole .map-shift {
  position: absolute;
  inset: -26%;
  will-change: transform;
}

/* Supersampling. The map is laid out at twice the size it is shown at and
   scaled back down, which makes MapLibre pick tiles one zoom level deeper —
   minor roads and buildings that simply are not in the data at the zoom this
   view actually sits at. Paired with a halved pixel ratio in main.js it draws
   exactly the same number of pixels as before, so it is detail for free
   rather than detail for frame rate. */
.porthole .map {
  position: absolute;
  top: 0;
  left: 0;
  width: 200%;
  height: 200%;
  transform: scale(0.5);
  transform-origin: 0 0;
}

.map .maplibregl-ctrl-attrib, .map .maplibregl-ctrl { display: none; }

/* Visual only. This is a MapLibre marker pinned to the patch coordinates,
   so the map positions it — it must stay on its point when the camera moves
   somewhere else, as it does on the end-of-round reveal. */
.crosshair {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 2px solid var(--ink);
  background: rgba(246, 245, 240, 0.85);
  box-shadow: 0 0 0 2px rgba(246, 245, 240, 0.55);
  pointer-events: none;
  z-index: 3;
}

/* Paper grain: near-invisible noise, multiply blend, atlas warmth */
.grain {
  position: absolute;
  inset: 20px;
  border-radius: 70px;
  pointer-events: none;
  z-index: 1;
  mix-blend-mode: multiply;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
}

/* Inner pane: acrylic lip, rim shadow, glass streak */
.glass {
  position: absolute;
  inset: 20px;
  border-radius: 70px;
  pointer-events: none;
  z-index: 2;
  box-shadow:
    inset 0 0 0 1px rgba(24, 39, 67, 0.18),
    inset 0 3px 14px rgba(24, 39, 67, 0.30),
    inset 0 -6px 18px rgba(24, 39, 67, 0.14),
    inset 0 0 0 6px rgba(253, 252, 248, 0.28);
  background:
    linear-gradient(150deg, rgba(255, 255, 255, 0.30) 0%, rgba(255, 255, 255, 0.06) 26%, rgba(255, 255, 255, 0) 45%);
}

.window-meta {
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 8px 0;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.view-dots { display: flex; gap: 7px; }

.view-dots .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid var(--ink-faint);
  transition: background 0.3s ease, border-color 0.3s ease;
}

.view-dots .dot.used { background: var(--ink); border-color: var(--ink); }

.attribution { font-size: 10px; color: var(--ink-faint); }

/* Guess area: centered under the window */
.guess-area { width: min(92vw, 430px); margin: 16px auto 0; position: relative; }

.guess-box { position: relative; display: flex; gap: 8px; }

#guessInput {
  flex: 1;
  min-width: 0;
  font-size: 16px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  color: var(--ink);
  outline: none;
}

#guessInput:focus { border-color: var(--ink-soft); }

#guessBtn {
  font-size: 15px;
  font-weight: 600;
  padding: 0 18px;
  border: none;
  border-radius: 12px;
  background: var(--ink);
  color: var(--card);
  cursor: pointer;
}

#guessBtn:active { transform: translateY(1px); }

.suggestions {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 10px 28px rgba(24, 39, 67, 0.16);
  z-index: 10;
  max-height: 216px;
  overflow-y: auto;
}

.suggestions li {
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 15px;
  cursor: pointer;
}

.suggestions li.active, .suggestions li:hover { background: var(--parchment); }

.guesses { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }

.guess-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 10px 14px;
  animation: rowIn 0.35s ease both;
}

@keyframes rowIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

.guess-row .name { flex: 1; font-size: 15px; font-weight: 600; }

.guess-row .dir svg { display: block; width: 18px; height: 18px; }

.guess-row .dir { padding-right: 4px; }

.guess-row.correct { border-color: var(--good); }
.guess-row.correct .name { color: var(--good); }

.guess-row.shake, .guess-box.shake { animation: shake 0.3s ease; }

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-5px); }
  75% { transform: translateX(5px); }
}

/* Endcard: floats where the input was, over the top guess rows, so the
   result is visible without scrolling. */
/* Pulled UP over the window-meta row so the card's top edge covers the view
   dots and the attribution. Once the round is over the dots are spent - they
   report a count that can no longer change - and the result is what the eye
   should land on, so the card takes that band rather than starting below it.
   -30px = the 16px gap above .guess-area plus the meta row's own height. */
.endcard {
  position: absolute;
  top: -30px;
  left: 0;
  right: 0;
  z-index: 20;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 18px;
  text-align: center;
  box-shadow: 0 18px 44px rgba(24, 39, 67, 0.22);
  animation: popIn 0.35s ease both;
}

@keyframes popIn {
  from { opacity: 0; transform: translateY(-6px) scale(0.97); }
  to { opacity: 1; transform: none; }
}

.end-title {
  font-family: "Iowan Old Style", "Palatino", serif;
  font-size: 22px;
  font-weight: 700;
}

.end-sub { margin-top: 6px; font-size: 14px; color: var(--ink-soft); }

/* Three actions, ONE pill. Same geometry for all of them - full width, same
   radius, padding and type - exactly as the Strata endgame does it, so the
   column reads as a stack of equal buttons rather than a button, a caption
   and a chip. Only the colour separates them, and it carries the whole
   hierarchy: filled, outlined in the same ink, then outlined soft.
   Anything that changes here changes in all three. */
.end-actions { margin-top: 16px; }

.end-actions #shareBtn,
.end-actions #archiveBtn,
.end-actions #nextGameBtn {
  display: block;
  box-sizing: border-box;
  width: 100%;
  padding: 14px 26px;
  border-radius: 13px;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  line-height: normal;
  /* Transparent rather than none on the filled one: the outlined pills below
     carry a real 1.5px border, and matching the box keeps all three the same
     height instead of leaving the first 3px shorter. */
  border: 1.5px solid transparent;
}

.end-actions #archiveBtn,
.end-actions #nextGameBtn { margin-top: 8px; }

/* Primary. The only filled one, so Share still wins the press. */
.end-actions #shareBtn {
  color: var(--card);
  background: var(--ink);
  border-color: transparent;
  cursor: pointer;
  box-shadow: 0 5px 14px rgba(24, 39, 67, 0.14);
}

/* Second: outlined in the same ink, so it reads as Share's equal in shape but
   never competes with it for fill. */
.end-actions #archiveBtn {
  color: var(--ink);
  background: transparent;
  border-color: var(--ink);
}

/* Third: hand the finished player to the next daily rather than letting the
   run dead-end. Softer border and ink keep it clearly third, so the column
   still reads top to bottom. */
.end-actions #nextGameBtn {
  color: var(--ink-soft);
  background: transparent;
  border-color: rgba(74, 86, 112, 0.42);
}

/* How-to article: below the fold, formatted like the live game pages
   (max-w-4xl article, text-3xl tracking-tight h2, text-lg prose) */
.howto-content {
  max-width: 896px;
  margin: 0 auto;
  padding: 64px 16px 48px;
  width: 100%;
}

.howto-content h2 {
  margin: 48px 0 12px;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--ink);
}

.howto-content h2:first-child { margin-top: 0; }

.howto-content p {
  margin: 0 0 14px;
  font-size: 18px;
  line-height: 1.625;
  color: color-mix(in srgb, var(--ink) 85%, transparent);
  max-width: 65ch;
}

.howto-content strong { color: var(--ink); }

/* Numbered how-to steps. Matches Strata: the only long block of copy that
   stays open, because it is what a player scrolling mid-game came for. */
.howto-steps {
  margin: 20px 0 0;
  padding: 0;
  list-style: decimal inside;
  max-width: 65ch;
}
.howto-steps li {
  margin: 0 0 12px;
  font-size: 18px;
  line-height: 1.625;
  color: color-mix(in srgb, var(--ink) 85%, transparent);
}
.howto-steps li:last-child { margin-bottom: 0; }

/* Collapsed long-form sections. Native <details>, so the copy is in the
   initial HTML and indexed at full weight while the page stays short. */
.seo-sections { margin-top: 40px; }

.seo-section {
  border-top: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
  padding: 20px 0;
}
.seo-section > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  cursor: pointer;
  list-style: none;
}
.seo-section > summary::-webkit-details-marker { display: none; }
.seo-section > summary h2 {
  margin: 0;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.025em;
}
.seo-section .chev {
  flex: none;
  width: 20px;
  height: 20px;
  background: currentColor;
  color: var(--ink-faint);
  transition: transform 0.2s ease;
  /* Chevron drawn as a mask so it inherits colour and needs no inline SVG. */
  -webkit-mask: no-repeat center / 20px 20px
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 8l5 5 5-5'/%3E%3C/svg%3E");
  mask: no-repeat center / 20px 20px
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 8l5 5 5-5'/%3E%3C/svg%3E");
}
.seo-section[open] .chev { transform: rotate(180deg); }
.seo-body { padding-top: 16px; }
.seo-body p:last-child { margin-bottom: 0; }

/* FAQ rows sit a step down from section copy, as on Strata. */
.seo-body h3 {
  margin: 0 0 4px;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
}
.seo-body .faq-a {
  font-size: 14px;
  margin-bottom: 20px;
}
.seo-body .faq-a:last-child { margin-bottom: 0; }

.seo-rule {
  margin: 48px 0;
  border: 0;
  border-top: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
}

/* Crawl paths between games: always visible, never collapsed. */
.more-games {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin: 16px 0 0;
  padding: 0;
  list-style: none;
}
.more-games a {
  display: block;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  text-decoration: none;
  transition: border-color 0.2s ease, transform 0.2s ease;
}
.more-games a:hover {
  border-color: var(--ink-soft);
  transform: translateY(-1px);
}
.mg-title { display: block; font-weight: 600; color: var(--ink); }
.mg-blurb { display: block; margin-top: 2px; font-size: 14px; color: var(--ink-faint); }

@media (min-width: 640px) {
  .howto-content h2 { font-size: 30px; }
  .seo-section > summary h2 { font-size: 20px; }
  .more-games { grid-template-columns: 1fr 1fr; }
}

/* Site footer: replica of Footer.tsx (dark navy, 4 columns, bottom bar) */
.site-footer {
  background: #0d1b2a;
  color: #fff;
  margin: 12px -16px calc(-24px - env(safe-area-inset-bottom));
}

@media (min-width: 1240px) {
  .site-footer { margin: 12px -28px -28px; }
}

.footer-inner {
  max-width: 1152px;
  margin: 0 auto;
  padding: 40px 16px;
}

.footer-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 32px;
}

.footer-grid h2 {
  margin: 0 0 12px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
}

.footer-grid ul { list-style: none; margin: 0; padding: 0; }

.footer-grid li a {
  display: inline-block;
  padding: 8px 0;
  font-size: 14px;
  color: #fff;
  text-decoration: none;
  transition: color 0.15s ease;
}

.footer-grid li a:hover { color: #7cb3ff; }

.footer-bottom {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.55);
}

.footer-bottom-right { display: flex; align-items: center; gap: 16px; }

.footer-bottom-right a { color: rgba(255, 255, 255, 0.55); text-decoration: none; padding: 8px 0; }
.footer-bottom-right a:hover { color: #fff; }

.footer-fake-control {
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 8px;
  padding: 4px 10px;
  white-space: nowrap;
}

@media (min-width: 640px) {
  .footer-bottom { flex-direction: row; align-items: center; justify-content: space-between; }
}

@media (min-width: 768px) {
  .footer-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Tablet: let the window breathe past the phone cap */
@media (min-width: 700px) and (max-width: 1239px) {
  .porthole {
    width: min(58vw, 540px);
    height: min(72vw, 670px);
  }
  .guess-area { width: min(58vw, 540px); }
}

/* Landscape phones: window left, guesses right, window capped to viewport */
@media (orientation: landscape) and (max-height: 520px) and (max-width: 1239px) {
  .game {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    gap: 24px;
  }
  .window-wrap { margin: 0; padding-top: 0; }
  .porthole {
    height: min(calc(var(--frame-vh, 100dvh) * 0.74), 400px);
    width: auto;
    aspect-ratio: 4 / 5;
    border-radius: 56px;
    padding: 12px;
  }
  .porthole .aperture, .glass, .grain { inset: 12px; border-radius: 44px; }
  .guess-area { width: min(44vw, 360px); margin: 0; }
}

/* Desktop: rails pinned to the page edges, window centered in the viewport */
@media (min-width: 1240px) {
  .site { padding: 0 28px 28px; }
  /* Left padding lands "More Games" at 20px from the viewport edge, and the
     rail below it at 24px — the offsets the live game pages use. */
  .topbar { padding: 8px 20px; margin: 0 -28px; }
  .wordmark { font-size: 27px; }

  .layout {
    display: block;
    position: relative;
    width: 100%;
  }

  .rail {
    display: block;
    width: 210px;
    position: absolute;
    left: -4px;
    top: 10px;
  }

  .game { width: 470px; margin: 0 auto; }

  .guess-area { width: 470px; }

  .porthole {
    width: 470px;
    height: 585px;
    border-radius: 100px;
    padding: 22px;
  }

  .porthole .aperture, .glass, .grain { inset: 22px; border-radius: 80px; }

}


/* ---- Endcard additions ---- */
.end-kicker {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 6px;
}

/* ---- Archive page ---- */
/* A real page, not a modal: clicking Archive should land somewhere you can
   link to, share and press back out of. Card grid mirrors the Mapfold
   archive - puzzle number, date, and your own result, and nothing that would
   spoil a day you have not played. */
.archive-page {
  max-width: 1024px;
  margin: 0 auto;
  padding: 24px 16px 64px;
  width: 100%;
}

.archive-summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}
.archive-count { margin: 0; font-size: 14px; font-weight: 500; color: var(--ink-soft); }
.archive-count strong { color: var(--ink); font-weight: 700; }
.archive-today {
  flex: none;
  font-size: 14px;
  font-weight: 600;
  color: var(--warm);
  text-decoration: none;
}
.archive-today:hover { text-decoration: underline; }

.archive-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

.archive-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--card);
  text-decoration: none;
  color: var(--ink);
  transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}
.archive-card:hover {
  transform: translateY(-2px);
  border-color: var(--ink-soft);
  box-shadow: 0 6px 18px -8px rgba(24, 39, 67, 0.35);
}
/* Solved is marked in the game's accent, not in a success green: it is the
   same convention Strata uses, and /flyover/archive - the React copy of this
   same grid - resolves its accent to this navy, so the two archive surfaces
   have to agree. */
.archive-card.is-solved { border-color: rgba(24, 39, 67, 0.45); box-shadow: 0 0 0 1px rgba(24, 39, 67, 0.2); }
.archive-card.is-today { border-color: var(--ink-soft); }

.ac-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.ac-no { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
.ac-check {
  flex: none;
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
}
.ac-check svg { width: 12px; height: 12px; }

.ac-weekday { margin-top: 2px; font-size: 12px; color: var(--ink-soft); }
.ac-date { font-size: 14px; color: var(--ink-soft); }

.ac-status {
  align-self: flex-start;
  margin-top: 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: -0.01em;
  background: rgba(24, 39, 67, 0.04);
  color: var(--ink-soft);
  border: 1px solid var(--line);
}
.ac-status svg { width: 10px; height: 10px; }
.ac-status.is-solved {
  background: var(--ink);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 1px 2px rgba(24, 39, 67, 0.18);
}
.ac-status.is-lost { background: rgba(180, 85, 45, 0.12); color: var(--warm); border-color: rgba(180, 85, 45, 0.3); }

/* Every chip carries a leading indicator, as Strata's does: a check when the
   day is solved, otherwise a dot - filled when the day was played and lost,
   hollow when it has not been opened. Without it the unplayed chips read as
   flat labels rather than as one state in a set. */
.ac-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.ac-status:not(.is-lost) .ac-dot {
  background: none;
  box-shadow: inset 0 0 0 1px var(--ink-faint);
}

.archive-empty { color: var(--ink-soft); padding-top: 24px; }
.archive-note { margin-top: 24px; font-size: 12px; color: var(--ink-faint); }

@media (min-width: 640px) { .archive-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1024px) { .archive-grid { grid-template-columns: repeat(4, 1fr); } }

/* Framed inside FlightQ: the page supplies the article and the footer, so the
   copies built into this document would appear twice. */
.is-framed .howto-content,
.is-framed .site-footer { display: none; }
