:root {
  --mirthtile: #9bded8;       /* brand + primary actions */
  --mirthtile-soft: #c4ece6;  /* lighter mint — primary CTA hover lift */
  --mirthtile-deep: #5fb9b1;  /* darker mint — secondary hover / focus rings */
  --snapmint: #79c7a5;        /* success / win states */
  --nooksky: #8fcddb;         /* links / secondary base */
  --nooksky-deep: #357a82;    /* link text / secondary hover */
  --link-hover: #1d4c54;      /* link hover — darker teal, light theme */
  --ink: #191817;
  --muted: #5e5f5c;            /* darkened from #6f706d for WCAG AA on tiny text (now ~6.2:1 vs --surface) */
  --hairline: #ded5c9;
  --surface: #fffdf8;
  --bg: #fbf4ec;
  --accent-peach: #f2c6b6;
  --accent-lilac: #e8d6f3;
  --accent-blue: #cdeef7;
  --accent-amber: #ffb703;
  --accent-amber-soft: #ffc83d;
  --stage: #232323;
  --thumb-shadow: 0 3px 12px rgba(38, 30, 21, 0.1), 0 1px 2px rgba(38, 30, 21, 0.06);
  --thumb-shadow-hover: 0 12px 28px rgba(38, 30, 21, 0.17), 0 4px 10px rgba(38, 30, 21, 0.09);
}

/* ============================================================
   DARK THEME — applied via <html data-theme="dark"> set by the
   inline init script in layout.pug. Overrides the same token
   names so the entire site inherits the new palette without any
   per-component edits. First pass — tunable from here.
   ============================================================ */
:root[data-theme="dark"] {
  /* Text — warm off-white inverts of ink/muted, preserves brand warmth */
  --ink: #f5efe5;
  --muted: #a09f9c;

  /* Surfaces — warm near-black brown undertones, not flat charcoal */
  --bg: #161310;                /* page background — deepest tier */
  --surface: #1f1a16;           /* cards, dropdowns, elevated surfaces */
  --stage: #0d0b09;             /* puzzle canvas / extra-deep */

  /* Hairlines — low-opacity white reads cleaner than a solid grey on dark */
  --hairline: rgba(255, 255, 255, 0.10);

  /* Brand accents — slight lift so they keep contrast on dark surfaces.
     Mirthtile + nooksky base stay; the "deep" hover/text variants get
     pulled up significantly since the original darks fall apart on dark. */
  --mirthtile-soft: #afe1da;    /* dark-mode tuned: still lighter than base but holds its shape */
  --mirthtile-deep: #7fcfc7;
  --nooksky-deep: #7fb3bc;
  /* Dark mode flips the hover direction — lighter teal on dark surfaces
     for readability, rather than going even darker against an already
     dark background. */
  --link-hover: #c8e6ec;

  /* Amber stays bright on dark — swap to the softer variant by default
     so saturated yellow doesn't punch holes in the layout. */
  --accent-amber: #ffc83d;

  /* Shadows — reduce intensity, the warm-brown surfaces don't need
     heavy drop shadows to read as elevated. */
  --thumb-shadow: 0 2px 8px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.25);
  --thumb-shadow-hover: 0 10px 24px rgba(0, 0, 0, 0.5), 0 3px 8px rgba(0, 0, 0, 0.3);
}

/* Native form controls + scrollbars follow the theme.  */
:root[data-theme="dark"] {
  color-scheme: dark;
}

/* Brief surface fade when the user toggles the theme. Scoped via a
   class added by the settings-page JS so we don't transition on the
   initial page paint (which would cause a weird color animate-in). */
html.theme-transitioning,
html.theme-transitioning body,
html.theme-transitioning .home-hero-feature-meta,
html.theme-transitioning .gallery-meta,
html.theme-transitioning .category-meta,
html.theme-transitioning .dropdown-menu,
html.theme-transitioning .settings-section,
html.theme-transitioning .upload-dropzone,
html.theme-transitioning .home-hero-cta .btn-outline-success,
html.theme-transitioning #site-header,
html.theme-transitioning input,
html.theme-transitioning textarea,
html.theme-transitioning select {
  transition: background-color 0.22s ease, color 0.22s ease, border-color 0.22s ease !important;
}

/* Card surfaces in dark mode — the default --surface (#1f1a16) sits
   too close to --bg (#161310) for cards to read as elevated. Bumping
   the meta strip a step lighter is enough to lift the card; an outer
   glow on the container would render at a different radius than the
   inner pieces and create a doubled edge. */
:root[data-theme="dark"] .gallery-meta,
:root[data-theme="dark"] .category-meta,
:root[data-theme="dark"] .home-hero-feature-meta {
  background: #2a231d;
}

/* Dark-mode overrides for layered surfaces that hard-code a white
   background or a cream hover tint. Bootstrap's default .dropdown-menu
   uses #fff, and the brand cream hover tint (rgba(222,213,201,0.42))
   disappears on dark surfaces — these rules patch both at once. */
:root[data-theme="dark"] .dropdown-menu {
  background-color: var(--surface);
  border-color: var(--hairline);
  color: var(--ink);
}
:root[data-theme="dark"] .dropdown-menu .dropdown-item {
  color: var(--ink);
}
:root[data-theme="dark"] .dropdown-menu .dropdown-item:hover,
:root[data-theme="dark"] .dropdown-menu .dropdown-item:focus,
:root[data-theme="dark"] #site-header .nav-categories-menu .dropdown-item:hover,
:root[data-theme="dark"] #site-header .nav-categories-menu .dropdown-item:focus,
:root[data-theme="dark"] #site-header .nav-account-menu .dropdown-item:hover,
:root[data-theme="dark"] #site-header .nav-account-menu .dropdown-item:focus,
:root[data-theme="dark"] #puzzleNav .puzzle-toolbar-more .dropdown-item:hover,
:root[data-theme="dark"] #puzzleNav .puzzle-toolbar-more .dropdown-item:focus {
  background: rgba(255, 255, 255, 0.035);
  color: var(--ink);
}
:root[data-theme="dark"] .dropdown-divider {
  border-top-color: var(--hairline);
}

/* The profile-icon SVG is shipped as a black-on-transparent image used
   inside both the Sign-in pill and the account avatar pill. Since it
   loads via <img>, currentColor can't reach it — invert it in dark
   mode so the smiley reads as light against the dark surface. */
:root[data-theme="dark"] #site-header .nav-signin-icon,
:root[data-theme="dark"] #site-header .nav-account-avatar {
  filter: invert(0.92);
}

/* Nav link hover tint — the brand cream wash blooms way too bright on
   dark surfaces (reads as a medium grey pill instead of a subtle
   hover hint). Replace with a small white-on-dark tint. */
:root[data-theme="dark"] #site-header .navbar-nav.mr-auto .nav-link:hover,
:root[data-theme="dark"] #site-header .navbar-nav.mr-auto .nav-link:focus,
:root[data-theme="dark"] #site-header .navbar-nav.ml-auto .nav-link:hover,
:root[data-theme="dark"] #site-header .navbar-nav.ml-auto .nav-link:focus,
:root[data-theme="dark"] #site-header .nav-signin-link,
:root[data-theme="dark"] #site-header .nav-account-toggle {
  background: rgba(255, 255, 255, 0.04);
}
:root[data-theme="dark"] #site-header .navbar-nav.ml-auto .nav-link.nav-signin-link:hover,
:root[data-theme="dark"] #site-header .navbar-nav.ml-auto .nav-link.nav-signin-link:focus,
:root[data-theme="dark"] #site-header .nav-account-toggle:hover,
:root[data-theme="dark"] #site-header .nav-account-toggle:focus,
:root[data-theme="dark"] #site-header .nav-account-toggle[aria-expanded="true"] {
  background: rgba(255, 255, 255, 0.12);
}

/* =================================================================
   A11y baseline — skip link + universal focus ring
   ================================================================= */

/* Skip-to-content link — proper visually-hidden pattern (clip + 1px) so
   it's truly invisible at rest regardless of font size or padding. First
   Tab from any page reveals it; pressing Enter jumps past the nav to
   the main content. Keyboard-only users save 15+ Tabs per page. */
.skip-to-content {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.skip-to-content:focus,
.skip-to-content:focus-visible {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 9999;
  width: auto;
  height: auto;
  padding: 0.75rem 1.25rem;
  margin: 0;
  overflow: visible;
  clip: auto;
  clip-path: none;
  background: var(--ink);
  color: #fff;
  font-weight: 700;
  font-size: 0.95rem;
  text-decoration: none;
  border-radius: 8px;
  outline: 2px solid var(--mirthtile, #9bded8);
  outline-offset: 2px;
  box-shadow: 0 6px 18px -4px rgba(0, 0, 0, 0.35);
}

/* Universal :focus-visible fallback for any interactive element that
   doesn't define its own focus ring. Uses the mirthtile brand color
   for visibility on the cream surface. */
:focus-visible {
  outline: 2px solid var(--mirthtile, #9bded8);
  outline-offset: 2px;
}

/* Global form-control focus ring — was previously only scoped to auth
   modals. Now any .form-control across the site (CMS admin, contact
   form, make-puzzle form, search, etc.) gets the brand focus state. */
.form-control:focus {
  outline: none;
  border-color: var(--nooksky, #8fcddb);
  box-shadow: 0 0 0 3px rgba(143, 205, 219, 0.28);
}

html {
  /* Full-bleed sections extend to 100vw which includes the vertical
     scrollbar's width — clipping prevents horizontal overflow without
     breaking sticky positioning (unlike overflow-x: hidden). */
  overflow-x: clip;
}

body {
  font-family: "Nunito Sans", sans-serif;
  background-color: var(--bg);
  overscroll-behavior-x: none;
  /* Clip a few px of decorative overflow (gallery play-button SVGs) so the
     page has no horizontal scrollbar -- which would otherwise leave a gap
     below the fixed desktop anchor ad. */
  overflow-x: clip;
}

.ajaxlink {
  cursor: pointer;
  color: var(--nooksky-deep);
}

.ajaxlink:hover {
  text-decoration: underline;
  color: var(--nooksky-deep);
}

a {
  color: var(--nooksky-deep);
}

a:hover,
a:focus {
  color: var(--link-hover);
  text-decoration: none;
}

/* ===== Brand palette — Bootstrap success-class overrides =====
   The mint fill is the same in both themes, so the text needs a
   fixed dark color — using --ink (which flips to off-white in dark
   mode) leaves the label invisible on the mint pill. */
.btn-success,
.btn-success:disabled,
.btn-success.disabled {
  background-color: var(--mirthtile);
  border-color: var(--mirthtile);
  color: #191817;
}
.btn-success:hover,
.btn-success:not(:disabled):not(.disabled):active,
.btn-success:not(:disabled):not(.disabled).active,
.show > .btn-success.dropdown-toggle {
  background-color: var(--mirthtile-deep);
  border-color: var(--mirthtile-deep);
  color: #191817;
}
.btn-success:focus,
.btn-success.focus,
.btn-success:not(:disabled):not(.disabled):active:focus {
  box-shadow: 0 0 0 0.2rem rgba(155, 222, 216, 0.48);
}

.btn-outline-success {
  color: var(--nooksky-deep);
  border-color: var(--nooksky);
}
.btn-outline-success:hover,
.btn-outline-success:not(:disabled):not(.disabled):active,
.btn-outline-success:not(:disabled):not(.disabled).active {
  color: #fff;
  background-color: var(--nooksky);
  border-color: var(--nooksky);
}
.btn-outline-success:focus,
.btn-outline-success.focus,
.btn-outline-success:not(:disabled):not(.disabled):active:focus {
  box-shadow: 0 0 0 0.2rem rgba(77, 124, 254, 0.4);
}
.btn-outline-success:disabled,
.btn-outline-success.disabled {
  color: var(--nooksky-deep);
  background-color: transparent;
}

.text-success {
  color: var(--snapmint) !important;
}

.alert-success {
  background-color: #e4f5ec;
  border-color: #b8e3cd;
  color: #1f6b48;
}

/* ===== Auth modal polish ===== */
/* ---- Branded modal backdrop ---- */
.modal-content {
  border: 0;
}
.modal-backdrop {
  background-color: #9CDED8; /* mirthtile — brighter, less muddy */
}
.modal-backdrop.show {
  opacity: 0.9;
}
.modal.show {
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

#loginModal .modal-dialog,
#registerModal .modal-dialog {
  max-width: 560px;
}

/* ---- Share modal ---- */
#shareModal .share-modal-dialog {
  max-width: 480px;
}
#shareModal .share-modal-content {
  border: 0;
  border-radius: 18px;
  background: var(--surface);
  box-shadow: 0 24px 60px rgba(25, 24, 23, 0.2);
  overflow: hidden;
}
#shareModal .share-modal-header {
  align-items: center;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid rgba(222, 213, 201, 0.82);
  background: rgba(255, 253, 248, 0.92);
}
#shareModal .share-modal-title {
  color: var(--ink);
  font-size: 1.2rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0;
}
#shareModal .share-modal-close {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: -0.25rem -0.25rem -0.25rem auto;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 10px;
  color: var(--ink);
  opacity: 0.55;
  font-size: 1.4rem;
  line-height: 1;
  text-shadow: none;
  transition: background-color 0.14s ease, opacity 0.14s ease;
}
#shareModal .share-modal-close:hover,
#shareModal .share-modal-close:focus {
  background: rgba(222, 213, 201, 0.42);
  opacity: 1;
  outline: none;
}
#shareModal .share-modal-body {
  padding: 1rem 1.25rem 1.25rem;
}
#shareModal .share-modal-intro {
  margin: 0 0 0.85rem;
  color: var(--muted);
  font-size: 0.92rem;
}
#shareModal .share-links {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
#shareModal .share-modal-copy {
  margin-top: 0.4rem;
}
#shareModal .share-modal-link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  min-height: 44px;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: #fff;
  color: var(--ink);
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: left;
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(38, 30, 21, 0.04);
  transition: background-color 0.14s ease, border-color 0.14s ease, transform 0.14s ease, box-shadow 0.14s ease;
  cursor: pointer;
}
#shareModal .share-modal-link:hover,
#shareModal .share-modal-link:focus {
  background: rgba(155, 222, 216, 0.18);
  border-color: rgba(95, 185, 177, 0.55);
  color: var(--ink);
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 4px 10px rgba(38, 30, 21, 0.08);
  outline: none;
}
#shareModal .share-modal-link--accent {
  background: rgba(155, 222, 216, 0.45);
  border-color: rgba(95, 185, 177, 0.55);
}
#shareModal .share-modal-link--accent:hover,
#shareModal .share-modal-link--accent:focus {
  background: var(--mirthtile);
}
#shareModal .share-modal-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--ink);
}
#shareModal .share-modal-label {
  flex: 1 1 auto;
}
#shareModal .share-modal-toast {
  margin-top: 0.6rem;
  padding: 0.55rem 0.85rem;
  border-radius: 10px;
  background: rgba(155, 222, 216, 0.4);
  color: var(--ink);
  font-size: 0.88rem;
  font-weight: 700;
  text-align: center;
}

/* Dark mode — header had a hardcoded cream wash and each share link
   was pinned to #fff, both of which stayed light while the modal body
   flipped to the dark surface. Patch them to follow the theme. */
:root[data-theme="dark"] #shareModal .share-modal-header {
  background: rgba(255, 255, 255, 0.03);
  border-bottom-color: var(--hairline);
}
:root[data-theme="dark"] #shareModal .share-modal-link {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--hairline);
  color: var(--ink);
  box-shadow: none;
}
:root[data-theme="dark"] #shareModal .share-modal-link:hover,
:root[data-theme="dark"] #shareModal .share-modal-link:focus {
  background: rgba(155, 222, 216, 0.10);
  border-color: rgba(155, 222, 216, 0.32);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.32);
}
:root[data-theme="dark"] #shareModal .share-modal-link--accent {
  background: rgba(155, 222, 216, 0.18);
  border-color: rgba(155, 222, 216, 0.45);
}
:root[data-theme="dark"] #shareModal .share-modal-link--accent:hover,
:root[data-theme="dark"] #shareModal .share-modal-link--accent:focus {
  background: rgba(155, 222, 216, 0.28);
}
:root[data-theme="dark"] #shareModal .share-modal-close:hover,
:root[data-theme="dark"] #shareModal .share-modal-close:focus {
  background: rgba(255, 255, 255, 0.06);
}

#loginModal .auth-modal-content,
#registerModal .auth-modal-content {
  border: 0;
  border-radius: 18px;
  background: var(--surface);
  box-shadow: 0 24px 60px rgba(25, 24, 23, 0.2);
  overflow: hidden;
}

#loginModal .modal-header,
#registerModal .modal-header {
  align-items: center;
  padding: 1.25rem 1.5rem;
  border-bottom: 1px solid rgba(222, 213, 201, 0.82);
  background: rgba(255, 253, 248, 0.92);
}

#loginModal .modal-title,
#registerModal .modal-title {
  color: var(--ink);
  font-size: 1.35rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}

#loginModal .close,
#registerModal .close {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: -0.25rem -0.25rem -0.25rem auto;
  padding: 0;
  border-radius: 10px;
  color: var(--ink);
  opacity: 0.55;
  text-shadow: none;
  transition: background-color 0.14s ease, opacity 0.14s ease;
}

#loginModal .close:hover,
#registerModal .close:hover,
#loginModal .close:focus,
#registerModal .close:focus {
  background: rgba(222, 213, 201, 0.42);
  opacity: 1;
}

#loginModal .auth-modal-body,
#registerModal .auth-modal-body {
  padding: 1.5rem;
}

#loginModal .auth-google-button,
#registerModal .auth-google-button,
.forgot-password-card .auth-google-button {
  min-height: 54px;
  padding: 0.25rem 0 1rem;
  display: flex;
  justify-content: center;
}

#loginModal .auth-google-button iframe,
#registerModal .auth-google-button iframe,
.forgot-password-card .auth-google-button iframe {
  width: 100% !important;
  max-width: 400px;
}

#loginModal label,
#registerModal label {
  margin-bottom: 0.45rem;
  color: var(--ink);
  font-size: 0.92rem;
  font-weight: 800;
}

#loginModal .form-control,
#registerModal .form-control {
  min-height: 42px;
  height: 42px;
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  font-size: 1rem;
  box-shadow: inset 0 1px 0 rgba(38, 30, 21, 0.03);
  transition: border-color 0.14s ease, box-shadow 0.14s ease, background-color 0.14s ease;
}

#loginModal .form-control:hover,
#registerModal .form-control:hover {
  border-color: #c7bdae;
}

#loginModal .form-control:focus,
#registerModal .form-control:focus {
  border-color: var(--nooksky);
  background: #fff;
  box-shadow: 0 0 0 3px rgba(143, 205, 219, 0.28);
}

#loginModal .form-group,
#registerModal .form-group {
  margin-bottom: 1.05rem;
}

#loginModal .btn-primary,
#registerModal .btn-primary {
  width: 100%;
  min-height: 48px;
  padding: 0.65rem 1rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--accent-amber);
  color: var(--ink);
  font-weight: 800;
  font-size: 0.92rem;
  /* Match the home hero CTA style: uppercase + expanded tracking so
     the primary action reads as a brand button, not a generic form
     submit. */
  text-transform: uppercase;
  letter-spacing: 0.06em;
  box-shadow: 2px 2px 0 0 var(--ink);
  transition: background-color 0.12s ease, box-shadow 0.12s ease, transform 0.12s ease;
}

/* OR divider between Google sign-in and the email form. */
#loginModal .auth-divider,
#registerModal .auth-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0.25rem 0 1rem;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
#loginModal .auth-divider::before,
#loginModal .auth-divider::after,
#registerModal .auth-divider::before,
#registerModal .auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--hairline);
}

/* Password label with the Forgot link aligned to the right. */
#loginModal .auth-label-row,
#registerModal .auth-label-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}
#loginModal .auth-forgot-link {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
}
#loginModal .auth-forgot-link:hover,
#loginModal .auth-forgot-link:focus {
  color: var(--ink);
}

/* Demoted register link — a quiet inline switch, not a competing CTA. */
#loginModal .auth-switch-line,
#registerModal .auth-switch-line {
  margin: 1.25rem 0 0;
  text-align: center;
  color: var(--muted);
  font-size: 0.92rem;
}
#loginModal .auth-switch-line a,
#registerModal .auth-switch-line a {
  color: var(--ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 2px;
}
#loginModal .auth-switch-line a:hover,
#registerModal .auth-switch-line a:focus {
  text-decoration-thickness: 2px;
}

/* Sign-up callout — fresher, less highlighter-bright than text-success. */
#registerModal .auth-callout {
  margin: 0 0 1.1rem;
  color: var(--ink);
  font-size: 0.95rem;
  line-height: 1.45;
}
#registerModal .auth-callout strong {
  color: var(--ink);
  font-weight: 800;
}

/* Terms line under the primary CTA — quiet, low-emphasis. */
#loginModal .auth-terms-line,
#registerModal .auth-terms-line {
  margin: 0.85rem 0 0;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.45;
}
#loginModal .auth-terms-line a,
#registerModal .auth-terms-line a {
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Password show/hide toggle — small icon button inside the input's
   right padding. Eye icon swaps based on .is-revealed state. */
#loginModal .auth-password-wrap,
#registerModal .auth-password-wrap {
  position: relative;
}
#loginModal .auth-password-wrap .form-control,
#registerModal .auth-password-wrap .form-control {
  padding-right: 42px;
}
#loginModal .auth-password-toggle,
#registerModal .auth-password-toggle {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--muted);
  border-radius: 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 0.14s ease, background-color 0.14s ease;
}
#loginModal .auth-password-toggle:hover,
#loginModal .auth-password-toggle:focus,
#registerModal .auth-password-toggle:hover,
#registerModal .auth-password-toggle:focus {
  color: var(--ink);
  background: rgba(222, 213, 201, 0.32);
  outline: none;
}
.auth-password-icon {
  width: 18px;
  height: 18px;
}
.auth-password-icon--hide { display: none; }
.auth-password-toggle.is-revealed .auth-password-icon--show { display: none; }
.auth-password-toggle.is-revealed .auth-password-icon--hide { display: inline-block; }

/* Standalone auth pages (forgot password, reset password) — same card
   look as the auth modal so the experience feels consistent. */
.auth-page {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 3rem 1rem 4rem;
  min-height: calc(100vh - 200px);
}
.auth-page-card {
  width: 100%;
  max-width: 480px;
  background: var(--surface, #fffdf8);
  border-radius: 16px;
  padding: 2rem 1.75rem 1.75rem;
  box-shadow: 0 12px 30px -18px rgba(0, 0, 0, 0.25), 0 1px 0 rgba(0, 0, 0, 0.04);
}
.auth-page-title {
  margin: 0 0 0.5rem;
  font-size: 1.75rem;
  font-weight: 800;
  color: var(--ink);
}
.auth-page-lede {
  margin: 0 0 1.5rem;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.5;
}
.auth-page-card label {
  display: block;
  margin-bottom: 0.45rem;
  color: var(--ink);
  font-size: 0.92rem;
  font-weight: 800;
}
.auth-page-card .form-control {
  width: 100%;
  min-height: 42px;
  height: 42px;
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  font-size: 1rem;
  box-shadow: inset 0 1px 0 rgba(38, 30, 21, 0.03);
  transition: border-color 0.14s ease, box-shadow 0.14s ease, background-color 0.14s ease;
}
.auth-page-card .form-control:hover {
  border-color: #c7bdae;
}
.auth-page-card .form-control:focus {
  outline: none;
  border-color: var(--nooksky);
  background: #fff;
  box-shadow: 0 0 0 3px rgba(143, 205, 219, 0.28);
}
.auth-page-card .form-group {
  margin-bottom: 1.05rem;
}
.auth-page-card .form-text {
  margin-top: 0.4rem;
  font-size: 0.82rem;
}
.auth-page-card .btn-primary,
.auth-page-card .auth-primary-btn {
  width: 100%;
  min-height: 48px;
  padding: 0.65rem 1rem;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--accent-amber);
  color: var(--ink);
  font-weight: 800;
  font-size: 0.92rem;
  /* Match the home hero CTA style: uppercase + expanded tracking so
     the primary action reads as a brand button, not a generic form
     submit. */
  text-transform: uppercase;
  letter-spacing: 0.06em;
  box-shadow: 2px 2px 0 0 var(--ink);
  transition: background-color 0.12s ease, box-shadow 0.12s ease, transform 0.12s ease;
}
.auth-page-card .btn-primary:hover,
.auth-page-card .auth-primary-btn:hover {
  background: #f5b441;
}
.auth-page-card .btn-primary:active,
.auth-page-card .auth-primary-btn:active {
  transform: translate(1px, 1px);
  box-shadow: 1px 1px 0 0 var(--ink);
}
.auth-page-card .auth-switch-line {
  margin: 1.5rem 0 0;
  text-align: center;
  color: var(--muted);
  font-size: 0.92rem;
}

/* ============================================================
   Dark-mode patches for the auth surfaces (login/register modals
   + standalone /forgot-password and /reset-password pages).
   Lots of hardcoded #fff inputs and cream-wash modal headers in
   the base styles — these rules patch them all at once.
   ============================================================ */
:root[data-theme="dark"] #loginModal .modal-header,
:root[data-theme="dark"] #registerModal .modal-header {
  background: rgba(255, 255, 255, 0.03);
  border-bottom-color: var(--hairline);
}
:root[data-theme="dark"] #loginModal .close:hover,
:root[data-theme="dark"] #registerModal .close:hover,
:root[data-theme="dark"] #loginModal .close:focus,
:root[data-theme="dark"] #registerModal .close:focus {
  background: rgba(255, 255, 255, 0.06);
}

/* Text inputs: dark surface, light text, hairline border. */
:root[data-theme="dark"] #loginModal .form-control,
:root[data-theme="dark"] #registerModal .form-control,
:root[data-theme="dark"] .auth-page-card .form-control {
  background: #2a231d;
  color: var(--ink);
  border-color: var(--hairline);
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25);
}
:root[data-theme="dark"] #loginModal .form-control:hover,
:root[data-theme="dark"] #registerModal .form-control:hover,
:root[data-theme="dark"] .auth-page-card .form-control:hover {
  border-color: rgba(255, 255, 255, 0.18);
}
:root[data-theme="dark"] #loginModal .form-control:focus,
:root[data-theme="dark"] #registerModal .form-control:focus,
:root[data-theme="dark"] .auth-page-card .form-control:focus {
  background: #2a231d;
  border-color: var(--nooksky);
  box-shadow: 0 0 0 3px rgba(143, 205, 219, 0.18);
}

/* Native autofill in webkit insists on a yellow tint — clamp it. */
:root[data-theme="dark"] #loginModal .form-control:-webkit-autofill,
:root[data-theme="dark"] #registerModal .form-control:-webkit-autofill,
:root[data-theme="dark"] .auth-page-card .form-control:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px #2a231d inset;
  -webkit-text-fill-color: var(--ink);
  caret-color: var(--ink);
}

/* Primary amber CTA — the border + shadow + text were all using --ink
   (which flips), so the button blew apart in dark mode. Pin them to
   fixed dark, matching the home hero Play button. */
:root[data-theme="dark"] #loginModal .btn-primary,
:root[data-theme="dark"] #registerModal .btn-primary,
:root[data-theme="dark"] .auth-page-card .btn-primary,
:root[data-theme="dark"] .auth-page-card .auth-primary-btn {
  border-color: #000;
  color: #000;
  box-shadow: 2px 2px 0 0 #000;
}
:root[data-theme="dark"] .auth-page-card .btn-primary:active,
:root[data-theme="dark"] .auth-page-card .auth-primary-btn:active {
  box-shadow: 1px 1px 0 0 #000;
}

/* "Sign in instead" / "Create an account" secondary CTA — the pastel
   blue fill is opaque enough to wash out the dark modal surface.
   Drop it to a translucent blue tint that reads as a subtle pill on
   dark, with brighter text + border. */
:root[data-theme="dark"] #loginModal .auth-switch-card a,
:root[data-theme="dark"] #registerModal .registerToLogin {
  background: rgba(143, 205, 219, 0.10);
  border-color: rgba(143, 205, 219, 0.32);
  color: var(--ink);
}
:root[data-theme="dark"] #loginModal .auth-switch-card a:hover,
:root[data-theme="dark"] #loginModal .auth-switch-card a:focus,
:root[data-theme="dark"] #registerModal .registerToLogin:hover,
:root[data-theme="dark"] #registerModal .registerToLogin:focus {
  background: rgba(143, 205, 219, 0.18);
  border-color: rgba(143, 205, 219, 0.55);
  color: var(--ink);
}

/* ============================================================
   Global dark-mode patches for Bootstrap defaults that aren't
   token-driven: modal contents, form inputs, tables, light
   buttons, footer. Anything not yet hand-styled in dark mode
   gets sensible defaults from these rules.
   ============================================================ */

/* Generic modal — Bootstrap defaults to #fff. */
:root[data-theme="dark"] .modal-content {
  background-color: var(--surface);
  color: var(--ink);
  border: 1px solid var(--hairline);
}
:root[data-theme="dark"] .modal-header,
:root[data-theme="dark"] .modal-footer {
  border-color: var(--hairline);
}
:root[data-theme="dark"] .modal-title {
  color: var(--ink);
}
:root[data-theme="dark"] .modal-content .close {
  color: var(--ink);
  text-shadow: none;
}

/* Generic .form-control — everywhere a user types. */
:root[data-theme="dark"] .form-control {
  background-color: #2a231d;
  color: var(--ink);
  border-color: var(--hairline);
}
:root[data-theme="dark"] .form-control:focus {
  background-color: #2a231d;
  color: var(--ink);
  border-color: var(--nooksky);
  box-shadow: 0 0 0 3px rgba(143, 205, 219, 0.18);
}
:root[data-theme="dark"] .form-control::placeholder {
  color: #7d756c;
}
:root[data-theme="dark"] .form-control:disabled,
:root[data-theme="dark"] .form-control[readonly] {
  background-color: #1a1612;
  color: var(--muted);
}
:root[data-theme="dark"] .form-control:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px #2a231d inset;
  -webkit-text-fill-color: var(--ink);
  caret-color: var(--ink);
}
:root[data-theme="dark"] .input-group-text {
  background-color: #1a1612;
  color: var(--muted);
  border-color: var(--hairline);
}

/* Native <select> — Bootstrap doesn't reset the OS-rendered chevron
   well in dark, so just flip surface + text. */
:root[data-theme="dark"] select.form-control {
  background-color: #2a231d;
  color: var(--ink);
}

/* Tables — used on the profile page (Previously played, Saved) and
   inside the congrats modal. */
:root[data-theme="dark"] .table {
  color: var(--ink);
}
:root[data-theme="dark"] .table th,
:root[data-theme="dark"] .table td {
  border-color: var(--hairline);
}
:root[data-theme="dark"] .table thead th {
  border-bottom-color: var(--hairline);
  color: var(--ink);
}
:root[data-theme="dark"] .table-hover tbody tr:hover {
  background-color: rgba(255, 255, 255, 0.04);
  color: var(--ink);
}
:root[data-theme="dark"] .table-striped tbody tr:nth-of-type(odd) {
  background-color: rgba(255, 255, 255, 0.02);
}

/* Bootstrap utility buttons that stay light by default. The
   "Options" dropdown toggles on profile cards use .btn-light. */
:root[data-theme="dark"] .btn-light {
  background-color: #2a231d;
  color: var(--ink);
  border-color: var(--hairline);
}
:root[data-theme="dark"] .btn-light:hover,
:root[data-theme="dark"] .btn-light:focus {
  background-color: #332a23;
  color: var(--ink);
  border-color: rgba(255, 255, 255, 0.18);
}
:root[data-theme="dark"] .btn-secondary {
  background-color: #2a231d;
  color: var(--ink);
  border-color: var(--hairline);
}

/* Bootstrap alert defaults — replace the eye-searing tinted bands
   with subtle versions that read on the dark surface. */
:root[data-theme="dark"] .alert-success {
  background-color: rgba(121, 199, 165, 0.14);
  color: var(--ink);
  border-color: rgba(121, 199, 165, 0.32);
}
:root[data-theme="dark"] .alert-danger {
  background-color: rgba(238, 100, 100, 0.14);
  color: var(--ink);
  border-color: rgba(238, 100, 100, 0.34);
}
:root[data-theme="dark"] .alert-info,
:root[data-theme="dark"] .alert-primary {
  background-color: rgba(155, 222, 216, 0.14);
  color: var(--ink);
  border-color: rgba(155, 222, 216, 0.32);
}
:root[data-theme="dark"] .alert-warning {
  background-color: rgba(255, 200, 61, 0.14);
  color: var(--ink);
  border-color: rgba(255, 200, 61, 0.32);
}

/* Bootstrap pagination — used on the category page. */
:root[data-theme="dark"] .pagination .page-link {
  background-color: var(--surface);
  color: var(--ink);
  border-color: var(--hairline);
}
:root[data-theme="dark"] .pagination .page-link:hover {
  background-color: rgba(255, 255, 255, 0.06);
  color: var(--ink);
  border-color: var(--hairline);
}
:root[data-theme="dark"] .pagination .page-item.active .page-link {
  background-color: var(--ink);
  color: var(--surface);
  border-color: var(--ink);
}
:root[data-theme="dark"] .pagination .page-item.disabled .page-link {
  background-color: var(--surface);
  color: var(--muted);
  border-color: var(--hairline);
}

/* Hairline rules. */
:root[data-theme="dark"] hr {
  border-color: var(--hairline);
}

/* Footer ships from the shared heygg.css with a light cream
   background and dark text — flip it to match the page. */
:root[data-theme="dark"] footer.heygg-body {
  background-color: var(--bg);
  color: var(--ink);
}
:root[data-theme="dark"] footer.heygg-body * {
  color: inherit;
  border-color: var(--hairline);
}
:root[data-theme="dark"] footer.heygg-body a {
  color: var(--ink);
  opacity: 0.78;
}
:root[data-theme="dark"] footer.heygg-body a:hover {
  opacity: 1;
  color: var(--ink);
}

/* Puzzle "You did it!" congrats overlay — hardcoded white bg with
   #333 text + #ccc dividers. Convert to tokens. */
:root[data-theme="dark"] #congrats {
  background: rgba(31, 26, 22, 0.97);
  color: var(--ink);
  box-shadow: 0 0 44px 5px rgba(0, 0, 0, 0.75);
}
:root[data-theme="dark"] #congrats .congrats_text {
  color: var(--ink);
}
:root[data-theme="dark"] #congrats hr.dotted-border {
  border-top-color: var(--hairline);
}
:root[data-theme="dark"] #congrats .highscore-body {
  border-top-color: var(--hairline);
  border-bottom-color: var(--hairline);
}
:root[data-theme="dark"] #congrats .table-sm td,
:root[data-theme="dark"] #congrats .table-sm th {
  color: var(--ink);
  border-color: var(--hairline);
}
:root[data-theme="dark"] #congrats .jumbotron {
  background-color: rgba(255, 255, 255, 0.04);
  color: var(--ink);
}

/* Blog inline <code> — the cream wash disappears on dark surface.
   Code blocks (<pre>) already use #1a1a1a which works in both modes. */
:root[data-theme="dark"] .blog-prose code {
  background: rgba(255, 255, 255, 0.08);
  color: var(--ink);
}

/* Generic Bootstrap surfaces that hard-code light backgrounds. */
:root[data-theme="dark"] .bg-light {
  background-color: var(--surface) !important;
  color: var(--ink);
}
:root[data-theme="dark"] .bg-white {
  background-color: var(--surface) !important;
  color: var(--ink);
}
:root[data-theme="dark"] .text-dark {
  color: var(--ink) !important;
}
:root[data-theme="dark"] .text-muted {
  color: var(--muted) !important;
}
:root[data-theme="dark"] .jumbotron {
  background-color: var(--surface);
  color: var(--ink);
}
:root[data-theme="dark"] .card {
  background-color: var(--surface);
  color: var(--ink);
  border-color: var(--hairline);
}
:root[data-theme="dark"] .card-header,
:root[data-theme="dark"] .card-footer {
  background-color: rgba(255, 255, 255, 0.03);
  border-color: var(--hairline);
}

/* Image thumbnails — Bootstrap wraps thumbnails in white. */
:root[data-theme="dark"] .img-thumbnail {
  background-color: var(--surface);
  border-color: var(--hairline);
}

/* Bootstrap "badge" pills — keep the brand-warning yellow but
   pin the text so it doesn't disappear. */
:root[data-theme="dark"] .badge-warning {
  color: #000;
}
:root[data-theme="dark"] .badge-secondary {
  background-color: var(--surface);
  color: var(--ink);
}
.auth-page-card .auth-switch-line a {
  color: var(--ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.auth-page-card .auth-password-wrap {
  position: relative;
}
.auth-page-card .auth-password-wrap .form-control {
  padding-right: 42px;
}
.auth-page-card .auth-password-toggle {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--muted);
  border-radius: 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 0.14s ease, background-color 0.14s ease;
}
.auth-page-card .auth-password-toggle:hover,
.auth-page-card .auth-password-toggle:focus {
  color: var(--ink);
  background: rgba(222, 213, 201, 0.32);
  outline: none;
}

/* =================================================================
   Blog
   ================================================================= */

/* Shared page-level scaffolding for content/index pages. Used by blog,
   tag, search, from-users, about, terms, privacy, cookie-policy so they
   all read at the same hierarchy. */
.blog-page,
.tag-page,
.search-page,
.from-users-page,
.content-page {
  padding-top: 0.5rem;
  padding-bottom: 4rem;
}
.blog-page-header,
.tag-page-header,
.search-page-header,
.from-users-page-header,
.content-page-header {
  margin: 1.25rem 0 2rem;
}
.blog-page-title,
.tag-page-title,
.search-page-title,
.from-users-page-title,
.content-page-title {
  margin: 0 0 0.4rem;
  font-size: 2.25rem;
  font-weight: 800;
  color: var(--ink);
  line-height: 1.15;
}
.blog-page-lede,
.tag-page-lede,
.search-page-lede,
.from-users-page-lede,
.content-page-lede {
  margin: 0;
  max-width: 42rem;
  color: var(--muted);
  font-size: 1.05rem;
  line-height: 1.5;
}
/* Your account header — title block on the left, "Create a new
   puzzle" CTA right-aligned. The CTA mirrors the home hero secondary
   button style (chunky black outline + drop shadow + uppercase) so
   the brand voice carries through. */
.profile-page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.profile-page-header-text { min-width: 0; }
.profile-create-btn,
.profile-create-btn.btn,
.profile-create-btn.btn-success {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.7rem 1.25rem;
  border: 3px solid #000;
  border-radius: 12px;
  /* Mint fill (same as the brand .btn-success) with the chunky black
     border + drop shadow of a primary CTA. Fixed dark text since the
     mint stays light in both themes. */
  background: var(--mirthtile);
  color: #000;
  font-weight: 800;
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.1;
  box-shadow: 3px 3px 0 0 #000;
  transition: transform 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
  text-decoration: none;
}
.profile-create-btn:hover,
.profile-create-btn:focus {
  background: var(--mirthtile-deep);
  color: #000;
  text-decoration: none;
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 0 #000;
}
.profile-create-btn:active {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 0 #000;
}
@media (max-width: 599.98px) {
  .profile-page-header { gap: 0.85rem; }
  .profile-create-btn { align-self: flex-start; }
}

/* Section headings inside Your account — sit a step below the page H1
   but stronger than body text. Matches the rhythm of section heads on
   the blog post and content pages. */
.profile-section-title {
  margin: 1.5rem 0 0.85rem;
  font-size: 1.35rem;
  font-weight: 800;
  color: var(--ink);
  letter-spacing: -0.005em;
  line-height: 1.25;
}

.tag-page-empty,
.search-page-empty,
.from-users-page-empty {
  color: var(--muted);
  font-size: 1rem;
  margin: 2rem 0;
}

/* Content pages constrain the body column for readable line-length, just
   like blog posts. The .blog-prose typography applies inside the body. */
.content-page-body {
  max-width: 42rem;
}
.content-page-meta {
  margin: 0.25rem 0 0;
  color: var(--muted);
  font-size: 0.9rem;
  font-weight: 600;
}
.blog-empty {
  color: var(--muted);
  font-size: 1rem;
  margin: 2rem 0;
}
.blog-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}
@media (min-width: 768px) {
  .blog-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.5rem;
  }
}
.blog-card {
  display: block;
  background: var(--surface, #fffdf8);
  border: 1px solid var(--hairline, #e6e1d8);
  border-radius: 14px;
  padding: 1.5rem 1.5rem 1.4rem;
  color: var(--ink);
  text-decoration: none;
  transition: border-color 0.14s ease, box-shadow 0.14s ease, transform 0.14s ease;
}
.blog-card:hover,
.blog-card:focus {
  border-color: #c7bdae;
  box-shadow: 0 14px 14px -12px rgba(0, 0, 0, 0.18);
  transform: translateY(-1px);
  color: var(--ink);
  text-decoration: none;
}
.blog-card-body {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.blog-card-title {
  margin: 0;
  font-size: 1.3rem;
  line-height: 1.25;
  font-weight: 800;
  color: var(--ink);
}
.blog-card-meta {
  margin: 0;
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.blog-card-excerpt {
  margin: 0;
  color: var(--ink);
  font-size: 0.98rem;
  line-height: 1.55;
  opacity: 0.82;
}
.blog-card-readmore {
  margin-top: 0.25rem;
  color: var(--ink);
  font-weight: 700;
  font-size: 0.92rem;
  letter-spacing: 0.01em;
}

/* Blog post (single) */
.blog-post-page {
  padding-top: 0.5rem;
  padding-bottom: 4rem;
}
.blog-post {
  max-width: 42rem;
  margin: 1.25rem auto 0;
}
.blog-post-header {
  margin-bottom: 2rem;
}
.blog-post-title {
  margin: 0 0 0.75rem;
  font-size: 2.4rem;
  line-height: 1.15;
  font-weight: 800;
  color: var(--ink);
}
.blog-post-byline {
  margin: 0;
  color: var(--muted);
  font-size: 0.95rem;
  font-weight: 600;
}
.blog-post-byline-sep {
  margin: 0 0.4rem;
  opacity: 0.6;
}
.blog-post-footer {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--hairline);
}
.blog-post-back {
  color: var(--ink);
  font-weight: 700;
  text-decoration: none;
}
.blog-post-back:hover,
.blog-post-back:focus {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Typography overrides for HTML content inside a blog post. Constrains
   line-length for readability and harmonizes the rich text with the
   rest of the site's typographic system. */
.blog-prose {
  font-size: 1.075rem;
  line-height: 1.65;
  color: var(--ink);
}
.blog-prose > * + * {
  margin-top: 1.1em;
}
.blog-prose h2 {
  margin-top: 2.2em;
  margin-bottom: 0.5em;
  font-size: 1.55rem;
  font-weight: 800;
  line-height: 1.25;
}
.blog-prose h3 {
  margin-top: 1.8em;
  margin-bottom: 0.4em;
  font-size: 1.25rem;
  font-weight: 800;
  line-height: 1.3;
}
.blog-prose h4 {
  margin-top: 1.6em;
  margin-bottom: 0.3em;
  font-size: 1.08rem;
  font-weight: 800;
}
.blog-prose p {
  margin: 0 0 1.1em;
}
.blog-prose a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.blog-prose a:hover,
.blog-prose a:focus {
  text-decoration-thickness: 2px;
}
.blog-prose ul,
.blog-prose ol {
  margin: 0 0 1.1em;
  padding-left: 1.4em;
}
.blog-prose li {
  margin-bottom: 0.4em;
}
.blog-prose li::marker {
  color: var(--muted);
}
.blog-prose blockquote {
  margin: 1.5em 0;
  padding: 0.5em 0 0.5em 1.1em;
  border-left: 3px solid var(--mirthtile, #9bded8);
  color: var(--ink);
  font-style: italic;
  opacity: 0.92;
}
.blog-prose blockquote p:last-child {
  margin-bottom: 0;
}
.blog-prose code {
  padding: 0.15em 0.4em;
  border-radius: 4px;
  background: rgba(222, 213, 201, 0.42);
  font-size: 0.92em;
  font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}
.blog-prose pre {
  margin: 1.3em 0;
  padding: 1em 1.1em;
  border-radius: 10px;
  background: #1a1a1a;
  color: #f5f1e8;
  overflow-x: auto;
  font-size: 0.92em;
  line-height: 1.5;
}
.blog-prose pre code {
  padding: 0;
  background: transparent;
  color: inherit;
  font-size: inherit;
}
.blog-prose img {
  max-width: 100%;
  height: auto;
  border-radius: 10px;
  margin: 1.5em 0;
  display: block;
}
.blog-prose hr {
  margin: 2.5em 0;
  border: 0;
  border-top: 1px solid var(--hairline);
}
.blog-prose table {
  width: 100%;
  margin: 1.5em 0;
  border-collapse: collapse;
  font-size: 0.95em;
}
.blog-prose th,
.blog-prose td {
  padding: 0.55em 0.75em;
  border-bottom: 1px solid var(--hairline);
  text-align: left;
}
.blog-prose th {
  font-weight: 800;
  color: var(--ink);
}

/* =================================================================
   Error / 404 page
   ================================================================= */
.error-page {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 4rem 1.25rem 5rem;
  min-height: calc(100vh - 200px);
}
.error-page-inner {
  width: 100%;
  max-width: 36rem;
  text-align: center;
}
.error-code {
  margin: 0;
  font-size: clamp(5rem, 14vw, 8rem);
  line-height: 1;
  font-weight: 800;
  color: var(--ink);
  opacity: 0.12;
  letter-spacing: -0.02em;
}
.error-title {
  margin: 0.25rem 0 1rem;
  font-size: 1.85rem;
  font-weight: 800;
  color: var(--ink);
  line-height: 1.2;
}
.error-message {
  margin: 0 auto 2rem;
  max-width: 30rem;
  color: var(--muted);
  font-size: 1.05rem;
  line-height: 1.55;
}
/* Error page actions reuse .home-hero-cta — center them on the page. */
.error-actions.home-hero-cta {
  justify-content: center;
}

/* Dev-only stack trace. Collapsed by default so the page stays clean. */
.error-stack {
  margin-top: 3rem;
  text-align: left;
}
.error-stack summary {
  cursor: pointer;
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--muted);
  margin-bottom: 0.75rem;
}
.error-stack pre {
  padding: 1rem 1.1rem;
  background: #1a1a1a;
  color: #f5f1e8;
  border-radius: 10px;
  font-size: 0.82rem;
  line-height: 1.5;
  overflow-x: auto;
  font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}

#loginModal .btn-primary:hover,
#registerModal .btn-primary:hover,
#loginModal .btn-primary:focus,
#registerModal .btn-primary:focus {
  background: var(--accent-amber-soft);
  border-color: var(--ink);
  color: var(--ink);
  box-shadow: 3px 3px 0 0 var(--ink);
  transform: translate(-1px, -1px);
}

#loginModal .btn-primary:active,
#registerModal .btn-primary:active {
  box-shadow: 1px 1px 0 0 var(--ink);
  transform: translate(1px, 1px);
}

#loginModal .auth-switch-card,
#registerModal .auth-switch-card {
  margin: 0.25rem 0 0;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: transparent;
}

#loginModal .auth-switch-card a,
#registerModal .registerToLogin {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 0.65rem 1rem;
  border: 1px solid var(--nooksky);
  border-radius: 10px;
  background: rgba(205, 238, 247, 0.72);
  color: var(--nooksky-deep);
  font-weight: 800;
  text-decoration: none;
  transition: background-color 0.14s ease, border-color 0.14s ease, color 0.14s ease;
}

#loginModal .auth-switch-card a:hover,
#loginModal .auth-switch-card a:focus,
#registerModal .registerToLogin:hover,
#registerModal .registerToLogin:focus {
  background: rgba(205, 238, 247, 0.94);
  border-color: var(--nooksky-deep);
  color: var(--ink);
  text-decoration: none;
}

#loginModal a,
#registerModal a {
  font-weight: 700;
}

ol.breadcrumb {
  text-transform: capitalize;
}

.site-breadcrumbs {
  padding: 0.45rem 0 0.2rem;
}

.site-breadcrumb-list,
.breadcrumb.site-breadcrumb-list {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.38rem;
  padding: 0;
  margin: 0;
  list-style: none;
  background: transparent;
  border-radius: 0;
  color: var(--muted);
  font-size: 0.88rem;
  font-weight: 600;
  line-height: 1.35;
  text-transform: capitalize;
}

.site-breadcrumb-item,
.breadcrumb-item.site-breadcrumb-item {
  display: inline-flex;
  align-items: baseline;
  min-width: 0;
  color: var(--muted);
  padding-left: 0;
}

.site-breadcrumb-item + .site-breadcrumb-item::before,
.breadcrumb-item.site-breadcrumb-item + .breadcrumb-item.site-breadcrumb-item::before {
  content: "";
  width: 6px;
  height: 6px;
  margin-right: 0.35rem;
  padding-right: 0;
  border-top: 1.5px solid #a8a096;
  border-right: 1.5px solid #a8a096;
  /* align-self: center overrides the parent's align-items: baseline
     so the chevron centers in the line box instead of dropping to the
     text baseline. */
  transform: rotate(45deg);
  align-self: center;
}

.site-breadcrumb-item.active,
.breadcrumb-item.site-breadcrumb-item.active {
  color: var(--ink);
  font-weight: 700;
}

/* Opt-out for crumbs whose source text is already properly cased
   (e.g. "Cars and Transportation" from the DB). Without this they get
   double-capitalized into "Cars And Transportation" by the global rule
   on .site-breadcrumb-list / ol.breadcrumb. */
.breadcrumb-natural,
.site-breadcrumb-item.breadcrumb-natural {
  text-transform: none;
}

/* The active crumb is an <h1> (SEO / a11y reasons). Force it to inherit
   typography from the breadcrumb list so it doesn't render at Bootstrap's
   h1 default (2.5rem / 1.75rem mobile), which blows past the viewport.
   Using explicit font-size + !important to defeat the bootstrap rule
   even through aggressive browser caches. */
.site-breadcrumbs h1.site-breadcrumb-current,
nav.site-breadcrumbs .site-breadcrumb-current,
h1.site-breadcrumb-current,
.site-breadcrumb-current {
  display: inline !important;
  margin: 0 !important;
  padding: 0 !important;
  font-family: inherit !important;
  font-size: 0.88rem !important;
  font-weight: inherit !important;
  font-style: inherit !important;
  color: inherit !important;
  letter-spacing: inherit !important;
  line-height: 1.35 !important;
  vertical-align: baseline !important;
}

/* Title truncation: applies at every viewport. Ellipsis only engages
   when the title would overflow, so wider viewports still see it in
   full. The header + list + active li all need min-width:0 + overflow
   for the shrink chain to work end-to-end. */
.puzzle-page-header {
  max-width: 100%;
}
.puzzle-page-header .site-breadcrumbs,
.site-breadcrumbs {
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
}
.site-breadcrumb-list,
.breadcrumb.site-breadcrumb-list {
  flex-wrap: nowrap;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
}
.site-breadcrumb-list > .site-breadcrumb-item.active,
.site-breadcrumb-list > .breadcrumb-item.site-breadcrumb-item.active {
  flex: 1 1 0;
  min-width: 0;
  overflow: hidden;
}
.site-breadcrumb-item.active .site-breadcrumb-current {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  max-width: 100%;
}

.site-breadcrumb-item a,
.site-breadcrumb-item .nav-breadcrumb,
.breadcrumb-item.site-breadcrumb-item a {
  color: var(--nooksky-deep);
  text-decoration: none;
  transition: color 0.14s ease;
}

.site-breadcrumb-item a:hover,
.site-breadcrumb-item a:focus,
.site-breadcrumb-item .nav-breadcrumb:hover,
.site-breadcrumb-item .nav-breadcrumb:focus,
.breadcrumb-item.site-breadcrumb-item a:hover,
.breadcrumb-item.site-breadcrumb-item a:focus {
  color: var(--ink);
  text-decoration: none;
}

.flexContainer {
  display: flex;
}

.flexOne {
  flex: 1;
}

/* The canvas has explicit width/height HTML attributes (set by the
   puzzle library based on initial calculation). Without max-width
   constraints, those intrinsic dimensions can push the canvas wider
   than the viewport on narrow phones, dragging the puzzle-page-header
   and other siblings along with it. */
#gameContainer,
#canvasContainer {
  max-width: 100%;
  min-width: 0;
}
#myCanvas {
  min-height: 90vh;
  width: 100%;
  max-width: 100%;
  touch-action: none;
  user-select: none;
  -moz-user-select: none;        /* Firefox */
  -ms-user-select: none;         /* Internet Explorer */
  -khtml-user-select: none;      /* KHTML browsers (e.g. Konqueror) */
  -webkit-user-select: none;     /* Chrome, Safari, and Opera */
  -webkit-touch-callout: none;   /* Disable Android and iOS callouts */
}
/* Give the canvas more vertical room on mobile so pieces have space to
   scatter around the assembled frame. */
@media (max-width: 767.98px) {
  #myCanvas {
    min-height: 110vh;
  }
}

/* On /make-puzzle the canvas is empty until a photo is uploaded.
   Skip the 90vh reservation so the SEO landing copy below the
   dropzone is visible instead of being pushed below the fold. */
#canvasContainer:has(#createContainer) #myCanvas {
  min-height: 0;
}

#gameContainer {
  --puzzle-bg: #ffffff;
  --puzzle-texture: url("/images/bg-leather.jpg");
  --puzzle-texture-size: 480px auto;
  --puzzle-texture-blend: overlay;
  --puzzle-vignette: radial-gradient(
    ellipse 115% 95% at 50% 45%,
    rgba(255, 255, 255, 0.08) 0%,
    rgba(255, 255, 255, 0) 30%,
    rgba(0, 0, 0, 0.18) 70%,
    rgba(0, 0, 0, 0.36) 100%
  );

  background-color: var(--puzzle-bg);
  background-image: var(--puzzle-vignette), var(--puzzle-texture);
  background-size: 100% 100%, var(--puzzle-texture-size);
  background-repeat: no-repeat, repeat;
  background-blend-mode: normal, var(--puzzle-texture-blend);
  display: flex;
}

/* Material picker — independent of color. Wood themes (data-bg) override these. */
#gameContainer[data-material="leather"] {
  --puzzle-texture: url("/images/bg-leather.jpg");
  --puzzle-texture-size: 540px auto;
  --puzzle-texture-blend: overlay;
}
/* Light-colored leather: use soft-light so grain reads without darkening the
   underlying color. Multiply was pulling lights like cork/cream way off-hue. */
#gameContainer[data-material="leather"][data-bg="studio"],
#gameContainer[data-material="leather"][data-bg="cream"],
#gameContainer[data-material="leather"][data-bg="mirthtile"],
#gameContainer[data-material="leather"][data-bg="sage"],
#gameContainer[data-material="leather"][data-bg="cork"] {
  --puzzle-texture-blend: soft-light;
}
#gameContainer[data-material="wool"] {
  --puzzle-texture: url("/images/bg-wool.jpg");
  --puzzle-texture-size: 240px auto;
  --puzzle-texture-blend: overlay;
}
#gameContainer[data-material="solid"] {
  --puzzle-texture: none;
}

#gameContainer[data-bg="studio"]    { --puzzle-bg: #f4f1ec; }
#gameContainer[data-bg="cream"]     { --puzzle-bg: #f5ebd6; }
#gameContainer[data-bg="mirthtile"] { --puzzle-bg: #9bded8; }
#gameContainer[data-bg="sage"]      { --puzzle-bg: #9fb19a; }
#gameContainer[data-bg="cork"]      { --puzzle-bg: #d3b07c; }
#gameContainer[data-bg="slate"]     { --puzzle-bg: #5b6470; }
#gameContainer[data-bg="navy"]      { --puzzle-bg: #1f2a44; }
#gameContainer[data-bg="charcoal"]  { --puzzle-bg: #2b2b2b; }
#gameContainer[data-bg="walnut"] {
  --puzzle-bg: #3a2516;
  --puzzle-texture: url("/images/bg-walnut.jpg");
  --puzzle-texture-size: 2400px auto;
  --puzzle-texture-blend: normal;
  /* Stronger vignette so it reads against the opaque wood texture. */
  --puzzle-vignette: radial-gradient(
    ellipse 105% 85% at 50% 45%,
    rgba(255, 220, 180, 0.12) 0%,
    rgba(255, 220, 180, 0) 25%,
    rgba(0, 0, 0, 0.45) 70%,
    rgba(0, 0, 0, 0.72) 100%
  );
}
#gameContainer[data-bg="white-oak"] {
  --puzzle-bg: #d6b88f;
  --puzzle-texture: url("/images/bg-white-oak.jpg");
  --puzzle-texture-size: 2400px auto;
  --puzzle-texture-blend: normal;
  --puzzle-vignette: radial-gradient(
    ellipse 105% 85% at 50% 45%,
    rgba(255, 245, 220, 0.14) 0%,
    rgba(255, 245, 220, 0) 25%,
    rgba(60, 35, 15, 0.34) 70%,
    rgba(60, 35, 15, 0.60) 100%
  );
}

/* Fullscreen: center the canvas alone in the viewport. The toolbar and any
   below-canvas content (description, tags) get pulled out of normal flow so
   they don't shift the visual midpoint of the puzzle area. */
#gameContainer:fullscreen,
#gameContainer:-webkit-full-screen {
  align-items: center;
  justify-content: center;
  position: relative;
}
#gameContainer:fullscreen #canvasContainer,
#gameContainer:-webkit-full-screen #canvasContainer {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}
/* Toolbar floats at the top, doesn't influence canvas centering. */
#gameContainer:fullscreen #puzzleNav,
#gameContainer:-webkit-full-screen #puzzleNav {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
}
/* Hide page-level content that lives below the canvas while in fullscreen. */
#gameContainer:fullscreen .puzzle-page-header,
#gameContainer:fullscreen .puzzle-meta-block,
#gameContainer:fullscreen #puzzleHeroImage,
#gameContainer:-webkit-full-screen .puzzle-page-header,
#gameContainer:-webkit-full-screen .puzzle-meta-block,
#gameContainer:-webkit-full-screen #puzzleHeroImage {
  display: none !important;
}

#gameContainer:fullscreen #myCanvas,
#gameContainer:-webkit-full-screen #myCanvas {
  margin: auto;
}

.puzzle-bg-section {
  padding: 0.6rem 0.9rem 0.75rem;
  border-top: 1px solid var(--hairline, #e6e1d8);
  margin-top: 0.35rem;
  min-width: 280px;
}
.puzzle-bg-section-label,
.puzzle-bg-popover-label {
  display: block;
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted, #7a7567);
  margin-bottom: 0.5rem;
}
.puzzle-bg-tabs {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.25rem;
  margin-bottom: 0.55rem;
}
.puzzle-bg-tab {
  padding: 0.35rem 0.4rem;
  border: 1px solid var(--hairline, #e6e1d8);
  border-radius: 7px;
  background: var(--surface, #fffdf8);
  color: var(--ink, #1a1a1a);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}
.puzzle-bg-tab:hover {
  background: rgba(155, 222, 216, 0.18);
}
.puzzle-bg-tab[aria-pressed="true"] {
  background: var(--mirthtile, #9bded8);
  border-color: var(--mirthtile-deep, #5fb9b1);
  /* Mint fill stays light in both themes — pin label color so it
     doesn't flip to off-white and disappear in dark mode. */
  color: #191817;
}
.puzzle-bg-swatch-set[hidden] { display: none; }
.puzzle-bg-swatches {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(36px, 1fr));
  gap: 0.45rem;
}
.puzzle-bg-swatches--wood {
  grid-template-columns: repeat(2, 1fr);
}
.puzzle-bg-swatches--wood .puzzle-bg-swatch {
  aspect-ratio: 16 / 10;
}
.puzzle-bg-swatch {
  width: 100%;
  min-width: 36px;
  aspect-ratio: 1 / 1;
  border: 1.5px solid rgba(0, 0, 0, 0.15);
  border-radius: 8px;
  padding: 0;
  cursor: pointer;
  background-clip: padding-box;
  transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease;
}
.puzzle-bg-swatch[data-bg="default"] {
  background-image: linear-gradient(45deg, #fff 49%, #d33 49%, #d33 51%, #fff 51%);
}
.puzzle-bg-swatch:hover {
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18);
}
.puzzle-bg-swatch[aria-pressed="true"] {
  border-color: var(--ink, #1a1a1a);
  box-shadow: 0 0 0 2px var(--ink, #1a1a1a) inset, 0 0 0 1px #fff inset;
}

.puzzle-bg-popover {
  position: fixed;
  z-index: 1080;
  background: #fff;
  border: 1px solid var(--hairline, #e6e1d8);
  border-radius: 12px;
  padding: 0.8rem 0.95rem 0.9rem;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.22);
  min-width: 280px;
  display: block;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s linear 0.16s;
}
.puzzle-bg-popover.show {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s;
}
.puzzle-bg-popover .puzzle-bg-swatches { grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); }
.puzzle-bg-popover .puzzle-bg-swatch { min-width: 40px; border-radius: 9px; }

#canvasContainer {
  flex: 1;
}

#thumbnailContainer {
  display: none;
}

.processing {
  width: 70px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

.navbar {
  padding: 0.1em 1rem;
}

#site-header:not([style]) {
  background-color: var(--surface);
  border-bottom: 1px solid var(--hairline);
}

/* Mobile (<md, navbar collapsed): flatten the account dropdown so the
   items (My Puzzles / Settings / Admin / Sign out) render as plain
   nav-link rows instead of hiding behind a smiley toggle. The hamburger
   panel already gives a vertical-list affordance, so a second collapse
   layer inside it just adds friction. */
@media (max-width: 767.98px) {
  #site-header .nav-account .nav-account-toggle {
    display: none;
  }

  #site-header .nav-account .nav-account-menu {
    display: block;
    position: static;
    float: none;
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    box-shadow: none;
    background: transparent;
  }

  /* Match the main mobile nav-link typography (1.5rem / 800) so the
     account destinations read as flat siblings of Daily Puzzle /
     Categories / Make Puzzles, not a small secondary tier. */
  #site-header .nav-account .nav-account-menu .dropdown-item {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0.9rem 0.6rem;
    font-size: 1.5rem;
    font-weight: 800;
    line-height: 1.15;
    color: var(--ink);
  }

  #site-header .nav-account .nav-account-menu .dropdown-divider {
    margin: 0.5rem 0;
  }
}

.navbar-nav .nav-item {
  display: flex;
  align-items: center;
}

#site-header .navbar-nav.mr-auto {
  gap: 4px;
}

#site-header .nav-link {
  color: var(--ink);
  font-weight: 600;
  opacity: 0.94;
}

#site-header .nav-link:hover,
#site-header .nav-link:focus {
  color: var(--nooksky-deep);
  opacity: 1;
}

#site-header .navbar-nav.mr-auto .nav-link {
  border-radius: 8px;
  padding: 0.45rem 0.8rem;
  transition: background-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}

#site-header .navbar-nav.mr-auto .nav-link:hover,
#site-header .navbar-nav.mr-auto .nav-link:focus {
  background: rgba(222, 213, 201, 0.42);
  color: var(--ink);
}

/* Bootstrap's .navbar-light pins every nav-link state (default, hover,
   focus, show, active) to hardcoded near-black rgba(0,0,0,*) values.
   In dark mode that wins over our token-based color, so the Categories
   toggle reads as black when the dropdown opens. Override the whole
   cluster so the link follows --ink in every state. */
#site-header .navbar-light .navbar-nav .nav-link,
#site-header .navbar-light .navbar-nav .nav-link:hover,
#site-header .navbar-light .navbar-nav .nav-link:focus,
#site-header .navbar-light .navbar-nav .show > .nav-link,
#site-header .navbar-light .navbar-nav .nav-link.show,
#site-header .navbar-light .navbar-nav .active > .nav-link,
#site-header .navbar-light .navbar-nav .nav-link.active {
  color: var(--ink);
}
/* Re-apply the white-on-black brand accent on the .active pill,
   which the rule above would otherwise normalize. */
#site-header .navbar-light .navbar-nav.mr-auto .nav-link.active,
#site-header .navbar-light .navbar-nav.mr-auto .active > .nav-link {
  color: #000;
}

/* Active nav pill — high-contrast inversion in both themes:
   - Light mode: black pill + white text
   - Dark mode:  white pill + black text
   The `!important` is here on purpose: Bootstrap's .navbar-light
   cluster pins multiple nav-link states to hardcoded near-black, and
   we need the active link to read as a fixed brand accent regardless
   of which pseudo-class is also matching (hover/focus/show). The
   transition is killed so hovering the active link produces no
   animation either. */
#site-header .navbar-nav.mr-auto .nav-link.active,
#site-header .navbar-nav.mr-auto .nav-link.active:hover,
#site-header .navbar-nav.mr-auto .nav-link.active:focus,
#site-header .navbar-light .navbar-nav.mr-auto .nav-link.active,
#site-header .navbar-light .navbar-nav.mr-auto .nav-link.active:hover,
#site-header .navbar-light .navbar-nav.mr-auto .nav-link.active:focus,
#site-header .navbar-light .navbar-nav.mr-auto .active > .nav-link,
#site-header .navbar-light .navbar-nav.mr-auto .show > .nav-link.active {
  background: #000 !important;
  color: #fff !important;
  opacity: 1 !important;
  cursor: default;
  transform: none !important;
  transition: none !important;
}
:root[data-theme="dark"] #site-header .navbar-nav.mr-auto .nav-link.active,
:root[data-theme="dark"] #site-header .navbar-nav.mr-auto .nav-link.active:hover,
:root[data-theme="dark"] #site-header .navbar-nav.mr-auto .nav-link.active:focus,
:root[data-theme="dark"] #site-header .navbar-light .navbar-nav.mr-auto .nav-link.active,
:root[data-theme="dark"] #site-header .navbar-light .navbar-nav.mr-auto .nav-link.active:hover,
:root[data-theme="dark"] #site-header .navbar-light .navbar-nav.mr-auto .nav-link.active:focus,
:root[data-theme="dark"] #site-header .navbar-light .navbar-nav.mr-auto .active > .nav-link,
:root[data-theme="dark"] #site-header .navbar-light .navbar-nav.mr-auto .show > .nav-link.active {
  background: #fff !important;
  color: #000 !important;
}

/* Tighten the mobile collapsed nav — Bootstrap's default leaves huge
   vertical gaps because each .nav-item gets full block height. */
@media (max-width: 767.98px) {
  #site-header .navbar-brand.main-logo img {
    width: 200px;
    height: auto;
  }
  #site-header .navbar-brand.main-logo .main-logo-svg {
    width: 200px;
    height: auto;
  }
  #site-header .navbar-collapse {
    padding: 0.5rem 0 0.75rem;
  }
  #site-header .navbar-nav .nav-item {
    display: block;
    margin: 0;
  }
  #site-header .navbar-nav .nav-item.dropdown {
    display: block;
  }
  #site-header .navbar-nav .nav-link {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0.9rem 0.6rem;
    font-size: 1.5rem;
    font-weight: 800;
    line-height: 1.15;
  }
  #site-header .nav-categories-menu .dropdown-item {
    display: flex;
    align-items: center;
    min-height: 44px;
    font-size: 1.25rem;
    padding: 0.6rem 0.75rem;
  }
  #site-header .nav-categories-link {
    display: flex;
    width: 100%;
    justify-content: space-between;
    align-items: center;
  }
  /* Mobile: collapse the dropdown completely when not shown, then expand
     in flow when .show. visibility:hidden was reserving vertical space. */
  #site-header .nav-categories-menu {
    display: block !important;
    position: static !important;
    inset: auto !important;
    transform: none !important;
    float: none !important;
    min-width: 0;
    width: 100%;
    margin: 0;
    padding: 0;
    border: none;
    box-shadow: none;
    background: transparent;
    grid-template-columns: 1fr;
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    visibility: hidden;
    transition: max-height 0.3s ease, opacity 0.2s ease, margin 0.3s ease, padding 0.3s ease, visibility 0s linear 0.3s;
  }
  #site-header .nav-categories-menu.show {
    max-height: 1000px;
    opacity: 1;
    visibility: visible;
    margin: 0.25rem 0 0.5rem;
    padding: 0.25rem 0;
    transition: max-height 0.4s ease, opacity 0.25s ease 0.05s, margin 0.3s ease, padding 0.3s ease, visibility 0s linear 0s;
  }
  #site-header .nav-categories-menu .dropdown-item {
    padding: 0.4rem 0.75rem;
  }
  #site-header .nav-categories-menu .dropdown-divider {
    margin: 0.4rem 0;
  }
  #site-header .nav-categories-menu .nav-categories-all {
    text-align: left;
  }
  /* Related Puzzles: cap to 2 on mobile */
  #relatedPuzzles .gal-col:nth-of-type(n+3) {
    display: none;
  }
  /* Prevent the page from scrolling horizontally on mobile — long titles
     and oversized children won't push the layout past the viewport. */
  html, body {
    overflow-x: hidden;
  }
  /* Truncate the current page title in the breadcrumb so it stays on one
     line. Anchored directly to the viewport so it doesn't depend on
     parent flex-shrink behavior. */
  .puzzle-page-header .site-breadcrumbs,
  .site-breadcrumbs {
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
  }
  .site-breadcrumb-list,
  .breadcrumb.site-breadcrumb-list {
    display: flex !important;
    flex-wrap: nowrap !important;
    align-items: baseline;
    max-width: 100%;
    min-width: 0;
    overflow: hidden;
  }
  .site-breadcrumb-list > .site-breadcrumb-item {
    flex: 0 0 auto;
    min-width: 0;
  }
  .site-breadcrumb-list > .site-breadcrumb-item.active,
  .site-breadcrumb-list > .breadcrumb-item.site-breadcrumb-item.active {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
  }
  .site-breadcrumb-item.active .site-breadcrumb-current {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
    max-width: 100%;
  }
  #site-header .nav-search.ml-md-4 {
    margin: 0 0 0.75rem !important;
    width: 100%;
    max-width: 100%;
    order: -1;
  }
  #site-header .nav-search .nav-search-input {
    flex: 1;
    width: 100%;
  }
  /* Make mobile nav a flex column so order: works on the search form */
  #site-header .navbar-collapse .navbar-nav.mr-auto {
    display: flex;
    flex-direction: column;
    align-items: stretch;
  }
  /* Divider above the account/login group on mobile */
  #site-header .navbar-collapse .navbar-nav.ml-auto {
    margin-top: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
  }
}

/* Mobile nav spark toggler — animation ported from Wordplete's burger.
   The star scales + rotates on hover, dims and rotates further when open,
   and the bars (burger/X) sit centered on top. */
#site-header .nav-spark-toggler {
  position: relative;
  padding: 0;
  margin: 0;
  width: 42px;
  height: 42px;
  border: none;
  background: transparent;
  color: var(--ink);
  outline: none;
  box-shadow: none;
  cursor: pointer;
}
#site-header .nav-spark-toggler:focus,
#site-header .nav-spark-toggler:active {
  outline: none;
  box-shadow: none;
}
#site-header .nav-spark-toggler:focus-visible {
  outline: 2px solid var(--mirthtile);
  outline-offset: 4px;
  border-radius: 8px;
}
#site-header .nav-spark-toggler svg {
  display: block;
}
#site-header .nav-spark-toggler .nav-spark-shape {
  fill: var(--mirthtile);
  transform-origin: 21px 21px;
  transition:
    transform 260ms cubic-bezier(0.34, 1.56, 0.64, 1),
    opacity 260ms ease,
    filter 260ms ease,
    fill 180ms ease;
}
#site-header .nav-spark-toggler .nav-spark-burger path,
#site-header .nav-spark-toggler .nav-spark-close path {
  transition:
    stroke 200ms cubic-bezier(0.6, 0, 0.4, 1),
    opacity 200ms cubic-bezier(0.6, 0, 0.4, 1);
}
/* Hover (closed) — bouncy scale + slight rotate + drop shadow */
#site-header .nav-spark-toggler:hover .nav-spark-shape {
  transform: scale(1.1) rotate(15deg);
  filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.15));
  fill: var(--mirthtile-deep);
}
/* Press (active) — quick squeeze */
#site-header .nav-spark-toggler:active .nav-spark-shape {
  transform: scale(0.95) rotate(0deg);
  transition: transform 120ms cubic-bezier(0.4, 0, 0.6, 1);
}
/* Open state — star rotates 45deg, dims, bars turn white */
#site-header .nav-spark-toggler[aria-expanded="true"] .nav-spark-shape {
  transform: scale(1) rotate(45deg);
  opacity: 0.35;
  transition:
    transform 290ms cubic-bezier(0.68, -0.3, 0.32, 1.4),
    opacity 290ms ease;
}
#site-header .nav-spark-toggler[aria-expanded="true"] .nav-spark-burger path,
#site-header .nav-spark-toggler[aria-expanded="true"] .nav-spark-close path {
  stroke: #ffffff;
}
/* Hover while open — extra rotate and dim */
#site-header .nav-spark-toggler[aria-expanded="true"]:hover .nav-spark-shape {
  transform: scale(1.1) rotate(55deg);
  opacity: 0.6;
}
/* Burger ↔ X swap stays display-based for clarity */
#site-header .nav-spark-toggler .nav-spark-close { display: none; }
#site-header .nav-spark-toggler[aria-expanded="true"] .nav-spark-burger { display: none; }
#site-header .nav-spark-toggler[aria-expanded="true"] .nav-spark-close { display: block; }

#site-header .navbar-nav.ml-auto .nav-link {
  color: var(--ink);
  border-radius: 8px;
  padding: 0.45rem 0.8rem;
  transition: background-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}

/* Sign in link — pairs the puzzle-style profile icon with the label.
   Carries a subtle default fill so it reads as an interactive CTA, not
   a plain text link. Hover deepens the wash. */
#site-header .nav-signin-link {
  display: inline-flex !important;
  align-items: center;
  gap: 0.45rem;
  background: rgba(222, 213, 201, 0.32);
}
#site-header .navbar-nav.ml-auto .nav-link.nav-signin-link:hover,
#site-header .navbar-nav.ml-auto .nav-link.nav-signin-link:focus {
  background: rgba(222, 213, 201, 0.6);
}
#site-header .nav-signin-icon {
  width: 18px;
  height: 18px;
  flex: none;
  display: inline-block;
}

/* PuzzleSnap logo — inline SVG. The mascot face keeps its brand yellow
   in both themes; the black face strokes + wordmark + tagline all use
   currentColor so the logo flips with the theme. */
#site-header .navbar-brand.main-logo {
  display: inline-flex;
  align-items: center;
  color: var(--ink);
}
#site-header .navbar-brand.main-logo .main-logo-svg {
  display: block;
  width: 160px;
  height: auto;
}
#site-header .navbar-brand.main-logo .logo-tagline {
  opacity: 0.55;
}

/* ============================================================
   Account settings page — /account/settings
   Lives on the .content-page scaffolding; adds section cards and
   a segmented control for the Theme picker (Light / Dark / Auto).
   ============================================================ */
.settings-page { display: flex; flex-direction: column; gap: 1.5rem; }
.settings-section {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  padding: 1.25rem 1.4rem;
  box-shadow: 0 1px 2px rgba(38, 30, 21, 0.04);
}
.settings-section-title {
  margin: 0 0 1rem;
  font-size: 1.05rem;
  font-weight: 800;
  letter-spacing: -0.005em;
  color: var(--ink);
}
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 0.4rem 0;
}
.settings-row + .settings-row { border-top: 1px solid var(--hairline); padding-top: 1rem; margin-top: 0.6rem; }
.settings-row-name { font-weight: 700; color: var(--ink); font-size: 0.96rem; }
.settings-row-help { color: var(--muted); font-size: 0.86rem; margin-top: 0.15rem; line-height: 1.4; }
.settings-row-control { flex: none; }
.settings-section-empty { color: var(--muted); font-size: 0.92rem; margin: 0; }
.settings-section-future { background: transparent; box-shadow: none; border-style: dashed; }
@media (max-width: 599.98px) {
  .settings-row { flex-direction: column; align-items: stretch; }
  .settings-row-control { width: 100%; }
}

/* Segmented control — used for Theme today; reusable for any 2-4 option pref. */
.settings-segmented {
  display: inline-flex;
  padding: 4px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--bg);
}
.settings-segmented-option {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.85rem;
  border: 0;
  background: transparent;
  border-radius: 999px;
  color: var(--muted);
  font-weight: 700;
  font-size: 0.88rem;
  cursor: pointer;
  transition: background 0.14s ease, color 0.14s ease;
}
.settings-segmented-option svg { width: 15px; height: 15px; flex: none; }
.settings-segmented-option:hover { color: var(--ink); }
.settings-segmented-option.is-active {
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(38, 30, 21, 0.08);
}
.settings-segmented-option:focus-visible {
  outline: 2px solid var(--mirthtile);
  outline-offset: 2px;
}

/* Sign-out button — matches the segmented-control pill language so it
   reads as part of the same settings vocabulary. Muted by default;
   destructive accent on hover so the consequence is visible without
   shouting. */
.settings-signout-btn {
  display: inline-flex;
  align-items: center;
  padding: 0.5rem 1.1rem;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--bg);
  color: var(--ink);
  font-weight: 700;
  font-size: 0.92rem;
  line-height: 1.2;
  text-decoration: none;
  transition: border-color 0.14s ease, color 0.14s ease, background 0.14s ease;
}
.settings-signout-btn:hover,
.settings-signout-btn:focus {
  border-color: #c0392b;
  color: #c0392b;
  background: var(--surface);
  text-decoration: none;
}
.settings-signout-btn:focus-visible {
  outline: 2px solid var(--mirthtile);
  outline-offset: 2px;
}

/* Account dropdown — signed-in mirror of the Sign-in pill. Same shape,
   same tint, same hover; opens a small dropdown with My Puzzles / Admin
   (if applicable) / Sign out instead of taking up two nav slots. */
#site-header .nav-account-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.7rem;
  background: rgba(222, 213, 201, 0.32);
  border: 1px solid transparent;
  border-radius: 999px;
  color: var(--ink);
  font-weight: 700;
  cursor: pointer;
  transition: background 0.14s ease, border-color 0.14s ease;
}
#site-header .nav-account-toggle:hover,
#site-header .nav-account-toggle:focus,
#site-header .nav-account-toggle[aria-expanded="true"] {
  background: rgba(222, 213, 201, 0.6);
  outline: none;
}
#site-header .nav-account-avatar {
  width: 20px;
  height: 20px;
  flex: none;
  display: inline-block;
}
#site-header .nav-account-chevron {
  width: 12px;
  height: 12px;
  flex: none;
  opacity: 0.65;
  transition: transform 0.18s ease, opacity 0.18s ease;
}
#site-header .nav-account-toggle[aria-expanded="true"] .nav-account-chevron {
  transform: rotate(180deg);
  opacity: 1;
}
#site-header .nav-account-menu {
  min-width: 180px;
  margin-top: 0.4rem;
  padding: 0.35rem;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: 0 12px 28px rgba(38, 30, 21, 0.14);
}
#site-header .nav-account-menu .dropdown-item {
  border-radius: 7px;
  padding: 0.5rem 0.7rem;
  color: var(--ink);
  font-weight: 600;
  font-size: 0.92rem;
}
#site-header .nav-account-menu .dropdown-item:hover,
#site-header .nav-account-menu .dropdown-item:focus {
  background: rgba(222, 213, 201, 0.42);
  color: var(--ink);
}
#site-header .nav-account-menu .dropdown-divider {
  margin: 0.3rem 0;
  border-top-color: var(--hairline);
}

/* Categories dropdown — 2-column grid since we have ~15 categories. */
.nav-categories-link {
  display: inline-flex !important;
  align-items: center;
  gap: 0.3rem;
}
.nav-categories-link::after { display: none !important; } /* hide Bootstrap caret */
.nav-categories-chevron {
  display: inline-block;
  width: 14px;
  height: 14px;
  flex: none;
  vertical-align: middle;
  opacity: 0.7;
  color: currentColor;
  transition: opacity 0.15s ease, transform 0.2s ease;
}
.nav-categories-chevron path { fill: currentColor; }
#site-header .nav-categories-dropdown:hover .nav-categories-chevron,
#site-header .nav-categories-link:focus .nav-categories-chevron,
#site-header .nav-categories-link[aria-expanded="true"] .nav-categories-chevron {
  opacity: 1;
}
#site-header .nav-categories-link[aria-expanded="true"] .nav-categories-chevron {
  transform: rotate(180deg);
}
.nav-categories-menu {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  gap: 0.1rem 0.8rem;
  min-width: 440px;
  margin-top: 0 !important;
  padding: 0.6rem;
  /* Surface token so the dropdown flips with the theme. Bootstrap's
     default .dropdown-menu background is hardcoded white, which leaves
     the menu reading as white-on-white in dark mode. */
  background: var(--surface);
  border-radius: 12px;
  border: 1px solid var(--hairline);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.12);
  /* Override the global toolbar dropdown fade so it doesn't fight Bootstrap here. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0s linear 0.15s;
}
.nav-categories-menu.show {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0s;
}
.nav-categories-menu .dropdown-item {
  padding: 0.45rem 0.65rem;
  border-radius: 6px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.2;
  transition: background-color 0.12s ease;
}
.nav-categories-menu .dropdown-item:hover,
.nav-categories-menu .dropdown-item:focus {
  background: rgba(222, 213, 201, 0.42);
  color: var(--ink);
}
.nav-categories-menu .dropdown-divider {
  grid-column: 1 / -1;
  margin: 0.4rem 0 0.25rem;
}
.nav-categories-menu .nav-categories-all {
  grid-column: 1 / -1;
  text-align: center;
  font-weight: 700;
  color: var(--ink);
}

#site-header .navbar-nav.ml-auto .nav-link:hover,
#site-header .navbar-nav.ml-auto .nav-link:focus {
  background: rgba(222, 213, 201, 0.42);
  color: var(--ink);
  text-decoration: none;
}

#site-header .nav-link.ajaxlink:hover,
#site-header .nav-link.ajaxlink:focus {
  text-decoration: none;
}

/* ===== Nav search pill ===== */
.nav-search {
  display: flex;
  align-items: center;
  width: 230px;
  max-width: 100%;
  background: transparent;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 4px 4px 4px 18px;
}

.nav-search:focus-within {
  box-shadow: 0 0 0 3px rgba(155, 222, 216, 0.38);
}

.nav-search-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  font-size: 0.95rem;
  color: var(--ink);
  outline: none;
  padding: 6px 8px 6px 0;
}

.nav-search-input::placeholder {
  color: #9a9a9a;
}

/* Replace the native WebKit "x" clear button with a Phosphor stroke icon */
.nav-search-input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  margin-right: 6px;
  cursor: pointer;
  background-color: var(--muted);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cline x1='200' y1='56' x2='56' y2='200' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='20'/%3E%3Cline x1='200' y1='200' x2='56' y2='56' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='20'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cline x1='200' y1='56' x2='56' y2='200' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='20'/%3E%3Cline x1='200' y1='200' x2='56' y2='56' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='20'/%3E%3C/svg%3E");
  -webkit-mask-size: contain;
          mask-size: contain;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
  opacity: 0.6;
  transition: opacity 0.14s ease, background-color 0.14s ease;
}
.nav-search-input::-webkit-search-cancel-button:hover {
  opacity: 1;
  background-color: var(--ink);
}

.nav-search-btn {
  flex: none;
  width: 38px;
  height: 38px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.nav-search-btn:hover {
  background: rgba(25, 24, 23, 0.06);
  color: var(--ink);
}

.nav-search-btn svg {
  width: 17px;
  height: 17px;
}

#previewContainer {
  position: absolute;
  bottom: 0px;
  border: 5px solid #eee;
  margin-left: 10px;
  background-color: #eee;
  display: none;
}

.puzzle-toggler {
  font-size: 0.875rem;
  padding: 0.15rem 0.3rem;
  line-height: 1.5;
}

#ot-sdk-btn.ot-sdk-show-settings,
#ot-sdk-btn.optanon-show-settings {
  font-size: 1em !important;
  color: var(--nooksky-deep) !important;
  padding: 0px !important;
  border: 0px !important;
}

#ot-sdk-btn.ot-sdk-show-settings:hover {
  background-color: white !important;
}

#timer {
  width: 55px;
  display: inline-block;
  text-align: left;
  margin-left: 5px;
}

#confetti-canvas {
  position: absolute;
  top: 0;
  z-index: 10000;
}

/* Phosphor-style close button — matches share / congrats modal pattern.
   Sits in the top-right of #previewContainer with a soft circle on hover. */
#previewClose {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  border-radius: 50%;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0.85;
  transition: background-color 0.14s ease, opacity 0.14s ease;
}
#previewClose:hover,
#previewClose:focus {
  background: rgba(0, 0, 0, 0.6);
  opacity: 1;
  outline: none;
}
#previewClose svg {
  width: 18px;
  height: 18px;
  display: block;
}

#previewImage {
  max-width: 40vw;
  max-height: 40vh;
}

#congratsClose {
  position: absolute;
  top: 6px;
  right: 10px;
  cursor: pointer;
  font-size: 24px;
  font-weight: bold;
  color: #999;
  line-height: 1;
  z-index: 201;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
}

#congratsClose:hover {
  color: #333;
}

#congrats .congrats-bottom {
  padding-top: 23px;
}

#congrats .btn {
  padding: 0.275rem 0.75rem;
  border-radius: 0.45rem;
}

#congrats .table-sm td {
  padding: 0.3rem 0;
}

#congrats .table-sm .bg-warning td:first-of-type {
  padding-left: 0.4rem;
}

#congrats .table-sm .bg-warning td:last-of-type {
  padding-right: 0.4rem;
}

#congrats .congrats-comment-input {
  border-color: #80bdff;
  box-shadow: 0 0 0 0.2rem rgb(0 123 255 / 25%);
}

/* Modal backdrop — fixed full-viewport tint that sits between the puzzle
   canvas (and confetti) and the #congrats modal. Mirrors the branded
   .modal-backdrop pattern above (mirthtile mint at 0.9 opacity + 4px
   blur) so the puzzle-complete modal feels consistent with the auth /
   share / contact modals. Animated via the `.is-open` class which a
   MutationObserver in puzzle-init.js toggles in sync with the modal's
   visibility. Click anywhere on the backdrop to dismiss the modal
   (re-uses the existing #congratsClose handler). */
.congrats-backdrop {
  position: fixed;
  inset: 0;
  background-color: #9CDED8;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 150;
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms ease-out;
}

.congrats-backdrop.is-open {
  opacity: 0.9;
  pointer-events: auto;
  cursor: pointer;
}

/* Hide WebKit/Blink scrollbar on the congrats modal — pairs with
   `scrollbar-width: none` (Firefox) and `-ms-overflow-style: none`
   (legacy Edge/IE) so the modal scrolls invisibly on every browser. */
#congrats::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}

#congrats {
  display: none;
  position: absolute;
  min-width: 40%;
  z-index: 200;
  top: 50%;
  left: 50%;
  transform: translate(-60%, -50%);
  background: rgba(255, 255, 255, 0.95);
  padding: 5vh 4vh 4vh 4vh;
  border-radius: 10px;
  /* Softer two-layer shadow — was 44px blur + 5px spread at 0.55-0.75
     opacity which read as too dramatic against the mint backdrop. */
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14), 0 2px 6px rgba(0, 0, 0, 0.06);
  text-align: center;
}

#congrats .congrats_text {
  color: #333;
  text-shadow: none;
  font-family: "Nunito Sans", sans-serif;
  font-weight: 900;
  font-size: 5vh;
}

#congrats .social_share {
  font-family: "Nunito Sans", sans-serif;
  font-weight: 900;
  font-size: 1.3em;
}

#congrats .congrats-stats {
  font-size: 1em;
}

#congrats hr.dotted-border {
  border-top: 1px dashed #ccc;
  margin-top: 0.25rem;
  margin-bottom: 0.25rem;
  width: 90%;
}

#congratsRelatedRow {
  margin-bottom: 15px;
}

#congratsRelatedRow .col {
  padding-left: 6px;
  padding-right: 6px;
}

.trophyHeadlines {
  font-family: "Nunito Sans", sans-serif;
  font-weight: 900;
}

.trophy-month-streak-labels {
  margin: 0 5px;
}

.trophy-month-streak-labels .col {
  padding: 0;
}

#congrats .congrats-stats .jumbotron {
  margin-bottom: 1rem;
}

#congrats .highscore-body {
  max-height: 150px;
  overflow-y: scroll;
  overflow-x: hidden;
  border-top: 1px solid #ccc;
  border-bottom: 1px solid #ccc;
  padding: 0 !important;
  margin: 0 !important;
  text-transform: capitalize;
}

#congrats .highscore-body .table {
  margin-bottom: 0rem;
}

.high-score-username {
  word-break: break-all;
}

/* ===== Congrats modal: compact overrides =====
   Inspired by the Queens Ultimate end-game modal — tighter typography,
   smaller padding, capped max-width, calmer banners. The goals are
   (1) modal fits in a single viewport at most screen sizes so the ad
   at the bottom hits IAB viewability easily, (2) hierarchy matches the
   Queens reference instead of the 5vh marquee headline that was
   dominating the modal. */
#congrats {
  padding: 16px 20px 14px;
  max-width: 420px;
  min-width: 320px;
  /* Never let the modal bleed past the viewport. If content somehow
     ends up taller than 100vh, the modal scrolls vertically instead of
     centering off-screen. Combined with the short-viewport media
     queries below, this keeps the ad reachable on every device.
     Scrollbar hidden cross-browser (same pattern Queens uses) so the
     modal stays visually clean. */
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  border-radius: 14px;
  /* Symmetric centering — the prior -60% horizontal offset was a
     leftover from an earlier sidebar layout that no longer applies. */
  transform: translate(-50%, -50%);
}

/* Desktop: a hair wider so the modal isn't dwarfed by the page. Mobile
   keeps the compact ~380px width by inheriting the base rule above. */
@media (min-width: 768px) {
  #congrats {
    min-width: 420px;
    max-width: 460px;
  }
  /* Widen the 3-tile picker to match — the tiles get a few extra px
     each so the photos read more clearly at desktop resolution. */
  .congrats-next-row {
    max-width: 380px;
  }
}

/* ===== Short-viewport collapsing — mirrors the heygg gcm-modal pattern =====
   Tightens padding, shrinks stat cards, hides the 2nd heygg rec so the
   ad stays above the fold on landscape phones / short laptops. */

/* Moderate squeeze — typical short laptop / smaller window */
@media (max-height: 720px) and (min-height: 621px) {
  #congrats {
    padding: 14px 18px 12px;
  }
  #congrats .congrats_text {
    font-size: 1.35rem;
  }
  #congrats .congrats-stats {
    margin: 4px 0 12px;
  }
  .congrats-statcard {
    min-height: 96px;
    padding: 16px 14px;
  }
  .congrats-statcard-value {
    font-size: 2rem;
  }
  .congrats-next-section {
    margin: 0 auto 8px;
  }
}

/* Aggressive squeeze — landscape mobile, very short windows */
@media (max-height: 620px) {
  #congrats {
    padding: 12px 16px 10px;
  }
  #congrats .congrats_text {
    font-size: 1.2rem;
  }
  #congrats .congrats-title {
    margin-bottom: 2px;
  }
  #congrats .congrats-stats {
    margin: 2px 0 8px;
  }
  .congrats-statcard {
    min-height: 84px;
    padding: 12px 12px;
  }
  .congrats-statcard-value {
    font-size: 1.7rem;
  }
  .congrats-statcard-label {
    margin-top: 3px;
  }
  .congrats-statcard-viewport {
    padding: 6px 0 14px;
  }
  .congrats-share-row {
    margin: 4px 0 0;
  }
  .congrats-share-button {
    padding: 5px 14px;
    font-size: 0.78rem;
  }
  .congrats-next-section {
    margin: 0 auto 6px;
  }
  .congrats-next-label {
    margin-bottom: 4px;
    font-size: 0.62rem;
  }
  /* Only show the first heygg cross-promo at very short heights —
     mirrors heygg's `.gcm-promo:nth-child(n+2) { display: none }` rule. */
  .heygg-recs .heygg-rec:nth-of-type(n+2) {
    display: none;
  }
  .heygg-recs {
    margin: 4px auto 4px;
  }
  .congrats-ad-slot {
    margin: 4px auto 0;
  }
}

#congrats .congrats_text {
  font-size: 1.55rem;
  font-weight: 800;
  letter-spacing: -0.015em;
  line-height: 1.2;
}

#congrats .congrats-title {
  margin-bottom: 4px;
}

/* Top-of-modal stat card — Queens Ultimate pattern. Time + Score (when
   present) sit side-by-side in a single rounded card, each cell a big
   value with a small uppercase label below it. Replaces the old "You
   scored X! Keep it up!" banner that duplicated the title's "you won
   in X" message. Lives in .congrats-stats (which was previously empty). */
#congrats .congrats-stats {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 4px 0 18px;
  font-size: 1em;
}

/* Override the legacy padding-top: 23px on .congrats-bottom — that
   was sized for the old leaderboard-table flow and now reads as a
   gaping whitespace. The intentional gap between the stat card and
   the "Try another puzzle" section lives in .congrats-stats's
   margin-bottom (above), not here. */
#congrats .congrats-bottom {
  padding-top: 0;
}

/* Peek-and-scale carousel matching the heygg GameCompleteModal pattern
   used on Queens. The track is transform: translateX'd by JS to center
   the active card; inactive cards peek at 0.85 scale + 0.5 opacity.
   Touch swipe + mouse drag are handled with pointer events in
   wireStatCardCarousel. */
.congrats-statcard-carousel {
  width: 100%;
  outline: none;
}

/* Subtle ring when the carousel is focused for keyboard navigation
   (ArrowLeft/ArrowRight). Only shows on keyboard focus, not pointer. */
.congrats-statcard-carousel:focus-visible {
  outline: 2px solid var(--mirthtile-deep, #5fb9b1);
  outline-offset: 4px;
  border-radius: 14px;
}

.congrats-statcard-viewport {
  overflow: hidden;
  /* Bleed slightly past the modal padding so peek cards have more room
     to be visible. Modal horizontal padding is 16-20px — these negative
     margins extend the viewport right to the modal edges. */
  margin: 0 -12px;
  /* Vertical padding gives the cards' drop shadow + the inactive cards'
     8px translateY room to breathe inside overflow:hidden. Without
     this, the shadow gets sliced flat at the viewport's bottom edge. */
  padding: 10px 0 22px;
}

.congrats-statcard-track {
  display: flex;
  gap: 8px;
  /* Easing matches heygg's gcm-carousel-track for a familiar feel. */
  transition: transform 0.25s cubic-bezier(0.34, 1.25, 0.64, 1);
  will-change: transform;
  touch-action: pan-y;  /* allow vertical page scroll, eat horizontal */
}

/* Desktop affordance — pointer-with-hand cursor signals the track is
   draggable. Mobile already discovers swipe through touch instinct. */
@media (hover: hover) {
  .congrats-statcard-track {
    cursor: grab;
  }
}

.congrats-statcard-track.is-dragging {
  transition: none;
  cursor: grabbing;
}

.congrats-statcard-track .congrats-statcard {
  flex: 0 0 65%;
  /* Match heygg's gcm-card transition stack — transform, opacity AND
     filter all animate together so the fan effect feels cohesive. */
  transition:
    transform 0.25s cubic-bezier(0.34, 1.25, 0.64, 1),
    opacity 0.25s ease,
    filter 0.25s ease;
  transform-origin: center bottom;
  user-select: none;
  -webkit-user-select: none;
}

/* Every card is clickable — peek cards advance to themselves, the
   active card advances to the next (wraps at end). Pointer cursor
   on all of them makes that obvious. */
.congrats-statcard-track .congrats-statcard {
  cursor: pointer;
}

.congrats-statcard-track.is-dragging .congrats-statcard {
  transition: none;
}

.congrats-statcard {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 110px;
  background: #fff;
  /* 2px border matches heygg's .gcm-card — gives more visual presence
     than a 1px hairline, especially against the mint backdrop. Color is
     the same warm grey heygg uses (--gcm-card-border #e8e3e2). */
  border: 2px solid #e8e3e2;
  border-radius: 12px;
  padding: 22px 16px;
  margin: 0;
  /* Heavier two-layer drop — Queens cards have a meaningful lift over
     the modal surface. The tight 0.10 layer defines the edge, the
     broad 0.12 halo gives the "floating" sense. */
  box-shadow:
    0 1px 3px rgba(0, 0, 0, 0.10),
    0 8px 24px rgba(0, 0, 0, 0.12);
  box-sizing: border-box;
}

.congrats-statcard-value {
  font-size: 2.4rem;
  font-weight: 800;
  letter-spacing: -0.025em;
  color: var(--ink);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.congrats-statcard-label {
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--muted, #636e72);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-top: 8px;
}

/* Pagination row — prev arrow + dot strip + next arrow. Matches the
   pattern Queens uses (heygg gcm-dots-prev/next + gcm-dot). */
.congrats-statcard-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  /* Tight — the viewport's bottom padding already gives breathing room
     between the cards and this row. */
  margin-top: 2px;
}

.congrats-statcard-dots {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
}

.congrats-statcard-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.18);
  border: 0;
  padding: 0;
  cursor: pointer;
  transition: background-color 0.2s ease-out, width 0.2s ease-out;
}

.congrats-statcard-dot:hover {
  background: rgba(0, 0, 0, 0.32);
}

/* Active dot is a brand-mint horizontal pill (~3x wider) — matches the
   Queens active-dot styling where the active position grows into a chip
   in the brand color. */
.congrats-statcard-dot.is-active {
  width: 22px;
  background: var(--mirthtile-deep, #5fb9b1);
}

/* Prev/next arrow buttons flanking the dots. Disabled (greyed out)
   when the carousel is at the corresponding edge. */
.congrats-statcard-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--muted, #636e72);
  font-size: 18px;
  line-height: 1;
  border-radius: 50%;
  cursor: pointer;
  transition: background-color 0.15s ease-out, color 0.15s ease-out;
}

.congrats-statcard-arrow:hover:not(:disabled) {
  background: rgba(0, 0, 0, 0.06);
  color: var(--ink, #191817);
}

.congrats-statcard-arrow:disabled {
  opacity: 0.32;
  cursor: default;
}

/* Comparison pill under each cell — only renders when timeCompare /
   scoreCompare is passed to buildStatCard. Green for positive
   ("faster than avg"), neutral grey otherwise. Backend currently
   doesn't supply this; the prop is wired for when /high-scores
   adds an avg_time field. */
.congrats-statcard-compare {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  margin-top: 6px;
  background: rgba(0, 0, 0, 0.05);
  color: var(--muted, #636e72);
  border-radius: 999px;
  font-size: 0.66rem;
  font-weight: 700;
  white-space: nowrap;
}

.congrats-statcard-compare.is-positive {
  background: rgba(58, 178, 119, 0.14);
  color: #2d8553;
}

/* "You ranked #X of Y" chip — sits ABOVE the stat card, centered. The
   block-on-its-own-line layout is achieved by the parent .congrats-stats
   having text-align: center (inherited from #congrats) and the pill
   being inline-flex with margin-bottom on a separate visual line from
   the statcard that follows. */
/* Share Score button — pill-styled, centered, lives below the stat
   card and above the "Try another puzzle" section. Uses Web Share API
   on supported platforms (most mobile, some desktop); falls back to
   clipboard copy with a brief "Copied!" confirmation. */
.congrats-share-row {
  display: flex;
  justify-content: center;
  margin: 10px 0 0;
}

.congrats-share-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px;
  background: rgba(0, 0, 0, 0.05);
  color: var(--ink, #191817);
  border: none;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  transition: background-color 0.12s ease-out;
}

.congrats-share-button:hover {
  background: rgba(0, 0, 0, 0.09);
}

.congrats-share-button svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

/* Show one icon per device — the clipboard glyph on desktop (because
   click copies), the iOS-style share glyph on mobile (because click
   opens the native share sheet). The query mirrors the one used by
   wireShareButton's runtime check so the visual and behavior always
   match. */
.congrats-share-icon-mobile { display: none; }
@media (hover: none) and (pointer: coarse) {
  .congrats-share-icon-desktop { display: none; }
  .congrats-share-icon-mobile { display: inline-block; }
}

.congrats-share-button.is-copied {
  background: rgba(58, 178, 119, 0.16);
  color: #2d8553;
}

.congrats-rank-pill svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

/* "Try another puzzle" section — small uppercase subhead above a
   3-tile thumbnail picker. Image-led; titles live in the tile's
   `title` attribute (hover) and aria-label (screen reader). */
.congrats-next-section {
  margin: 0 auto 10px;
}

.congrats-next-label {
  font-size: 0.66rem;
  font-weight: 700;
  color: var(--muted, #636e72);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  margin-bottom: 6px;
}

.congrats-next-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  max-width: 340px;
  margin: 0 auto;
}

.congrats-next-tile {
  display: block;
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface, #f0eee9);
  border: 1px solid var(--border, rgba(0, 0, 0, 0.06));
  isolation: isolate;
  transition: transform 0.12s ease-out, border-color 0.12s ease-out;
  text-decoration: none;
}

.congrats-next-tile:hover {
  border-color: var(--mirthtile-deep, #5fb9b1);
  transform: translateY(-1px);
  text-decoration: none;
}

.congrats-next-tile-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Same puzzle-piece overlay as .gallery-jigsaw on home/category
   thumbnails — etches the jigsaw grid pattern over the photo via
   mix-blend-mode so these tiles read as puzzles, not generic photos. */
.congrats-next-tile::after {
  content: '';
  position: absolute;
  inset: 0;
  background: url('/images/jigsaw-overlay-v3.svg') center / 100% 100% no-repeat;
  mix-blend-mode: overlay;
  opacity: 0.75;
  pointer-events: none;
  transition: opacity 0.2s ease-out;
}

@media (hover: hover) {
  .congrats-next-tile:hover::after {
    opacity: 1;
  }
}

/* Tighter highscore table */
#congrats .highscore-body {
  max-height: 110px;
}

#congrats .highscore-body th,
#congrats .highscore-body td {
  font-size: 0.78rem;
  padding: 0.25rem 0.4rem;
}

/* Compact primary "Play More Puzzles" / "Back to homepage" CTA — the
   appended HTML uses .btn-lg which is too dominant for this layout. */
#congrats .btn-lg {
  padding: 0.5rem 1.2rem;
  font-size: 0.95rem;
  margin-bottom: 12px !important;
}

/* Tighter "Play another Puzzle?" thumbnail row */
#congrats #congratsRelatedRow {
  margin-bottom: 8px;
}
#congrats .small.text-muted {
  font-size: 0.78rem;
  margin-bottom: 6px;
}

/* Spacing between the cross-promo recs block and the ad below. */
#congrats .heygg-recs {
  margin-top: 10px;
  margin-bottom: 10px;
}

/* Slim margins on the ad-slot inside the modal so it sits tight to the
   recommendations and doesn't push the modal taller than necessary. */
#congrats .congrats-ad-slot {
  margin-top: 10px;
  margin-bottom: 0;
}

.gallery {
  width: 100%;
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  isolation: isolate;
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  background: #fff;
}

.gallery span {
  display: block;
}

.gallery-feature {
  width: 100%;
  aspect-ratio: 4 / 3;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  background: #fff;
}

.gallery img,
.gallery-feature img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.gallery-meta {
  padding: 9px 10px 11px;
  /* Surface token so the strip flips with the theme — title (--ink)
     and stats (--muted) stay readable in both light + dark. */
  background: var(--surface);
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  transition: transform 0.14s ease-out, box-shadow 0.14s ease-out;
}
.gallery {
  transition: transform 0.14s ease-out;
}
/* Lift on hover. Both pieces transform together so the card moves as a
   single unit; the deeper shadow lives only on the footer to avoid
   conflicting glows above the image. */
@media (hover: hover) {
  .gallery-container:hover .gallery,
  .gallery-container:hover .gallery-meta {
    transform: translateY(-4px);
  }
  .gallery-container:hover .gallery-meta {
    /* High negative spread keeps the shadow strictly below the footer,
       never bleeding above its top edge into the image's side region. */
    box-shadow: 0 14px 14px -12px rgba(0, 0, 0, 0.22);
  }
}

.gallery-title {
  display: block;
  font-weight: 700;
  font-size: 0.92rem;
  line-height: 1.3;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.gallery-stat {
  display: block;
  font-size: 0.8rem;
  color: var(--muted);
  margin-top: 1px;
}

.gallery-jigsaw {
  position: absolute;
  inset: 0;
  background: url('/images/jigsaw-overlay-v3.svg') center / 100% 100% no-repeat;
  mix-blend-mode: overlay;
  /* Always visible so puzzle thumbnails consistently read as puzzles
     (not just on hover). Hover bumps to full strength. */
  opacity: 0.75;
  transition: opacity 0.2s ease-out;
  pointer-events: none;
}

@media (hover: hover) {
  .gallery-container:hover .gallery-jigsaw {
    opacity: 1;
  }
}

/* Hover stat overlay disabled — counts moved to the card footer / removed
   entirely as part of the unified card pass. */
.gallery-overlay {
  display: none;
}

.gallery .gallery-stat-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgba(255, 255, 255, 0.95);
  color: var(--ink);
  font-size: 0.74rem;
  font-weight: 800;
  padding: 4px 9px;
  border-radius: 999px;
}

.gallery-stat-pill svg {
  width: 11px;
  height: 11px;
}

.gallery .gallery-play-icon,
.gallery-feature .gallery-play-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  /* Cream circle pops against any puzzle thumbnail and stays the same
     in both themes — so the arrow inside is also pinned to a fixed
     dark color (rather than --ink, which would flip and disappear). */
  background: rgba(255, 253, 248, 0.95);
  color: #191817;
  border: none;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.9);
  transition: opacity 0.16s ease, transform 0.16s ease;
  pointer-events: none;
}

.gallery .gallery-play-icon svg,
.gallery-feature .gallery-play-icon svg {
  width: 18px;
  height: 18px;
  transform: translateX(1px);
}

/* Hero feature card is much larger than gallery thumbs — scale the play
   icon up proportionally so it doesn't feel lost in the middle. */
.gallery-feature .gallery-play-icon {
  width: 72px;
  height: 72px;
}
.gallery-feature .gallery-play-icon svg {
  width: 30px;
  height: 30px;
  transform: translateX(2px);
}

@media (hover: hover) {
  .gallery-container:hover .gallery-play-icon {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
}

#relatedPuzzles .col {
  max-width: 33%;
}

.play-button img {
  width: 10px;
}

/* The anchor is the click target. The .gallery (top) and .gallery-meta
   (bottom) children form the visible card together. Because col-*
   classes live on the anchor and add 15px padding, putting the card
   styling on the children lets that padding form the real gutter. */
.gallery-container {
  cursor: pointer;
  display: block;
  text-decoration: none;
  color: inherit;
  margin-bottom: 12px;
}

.gallery-container:hover,
.gallery-container:focus {
  text-decoration: none;
  color: inherit;
}

.caption {
  position: absolute;
  right: 0;
  bottom: 0px;
  width: 100%;
  padding: 5px;
  font-size: 0.8em;
  height: 45px;
  color: white;
}

.caption-title,
.caption-title:hover,
.caption-container span {
  color: white;
  filter: drop-shadow(0px 0px 2px #000);
}

.flex-caption {
  display: flex;
  overflow: ellipsis;
}

@media (hover: hover) {
  .gallery-container:hover {
    position: relative;
    z-index: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .gallery,
  .gallery-feature,
  .gallery-jigsaw,
  .gallery-overlay,
  .category-thumb {
    transition: none;
  }
}

.play-container {
  width: 25%;
}

.caption-container {
  width: 75%;
  height: 100%;
  overflow: hidden;
}

svg.play-puzzle {
  position: absolute;
  top: 0px;
  right: -10px;
  transform: rotate(35deg) scale(1.1);
  z-index: 1;
}

.play-label {
  position: absolute;
  right: 0px;
  top: 14px;
  color: white;
  font-weight: bold;
  z-index: 100;
}

.caption-title {
  font-weight: 600;
}

.public-puzzle-title {
  text-overflow: ellipsis;
  text-transform: capitalize;
  overflow: hidden;
  white-space: nowrap;
}

#puzzleNav .btn-group-sm > .btn,
.btn-sm {
  padding: 0.15rem 0.3rem;
}

#puzzleNav .dropdown {
  display: inline-block;
}

.puzzle-page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
  padding: 0.4rem 0.85rem 0.2rem;
  background-color: var(--surface, #fffdf8);
  position: relative;
  z-index: 1;
}

#puzzleNav.puzzle-game-toolbar {
  background-color: var(--surface, #fffdf8);
  border-bottom: 1px solid var(--hairline, #ded5c9);
  position: relative;
  z-index: 1;
}

.puzzle-page-header .puzzle-breadcrumbs,
.puzzle-page-header .site-breadcrumbs {
  padding: 0;
  flex: 1 1 auto;
  min-width: 0;
}

/* Toolbar surface (the collapse contents): horizontal at md+ desktop,
   vertical sheet on mobile. Scoped to md+ so Bootstrap's .collapse
   {display:none} still hides it on mobile until Menu is tapped. */
@media (min-width: 768px) {
  #puzzleNav .puzzle-toolbar-surface {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: nowrap;
  }
}
/* Timer lives as a sibling outside the collapse (so it stays visible
   on mobile). margin-left: auto pushes it to the right edge of the
   navbar at all breakpoints. */
#puzzleNav .puzzle-toolbar-timer-outer {
  margin-left: auto;
  padding-right: 0.85rem;
}
/* Section labels — only show inside the mobile menu sheet. */
#puzzleNav .puzzle-toolbar-section-label {
  display: none;
}

/* Mobile menu sheet: full-width vertical layout with grouped sections. */
@media (max-width: 767.98px) {
  #puzzleNav .puzzle-toolbar-section-label {
    display: block;
    width: 100%;
    font-size: 0.82rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
    margin: 1.25rem 0 0.6rem;
    text-align: left !important;
    align-self: stretch;
  }
  /* When Menu is tapped open on mobile, lay the sheet out vertically.
     Default state (.collapse not .show) stays display:none from Bootstrap. */
  #puzzleNav .puzzle-toolbar-surface.show,
  #puzzleNav .puzzle-toolbar-surface.collapsing {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    width: 100%;
    /* No horizontal padding — let the navbar's own gutter set the left
       edge so cards align flush with the Options pill above. */
    padding: 0.5rem 0 1rem;
    margin: 0;
    gap: 0;
  }
  /* Zero out any inherited indent on the inner groups too. */
  #puzzleNav .puzzle-toolbar-surface.show .puzzle-toolbar-group,
  #puzzleNav .puzzle-toolbar-surface.show .puzzle-toolbar-more,
  #puzzleNav .puzzle-toolbar-surface.show .puzzle-toolbar-section-label {
    padding-left: 0 !important;
    padding-right: 0 !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
  }
  /* Setup: Style + Difficulty selects side-by-side in a 2-col grid. */
  #puzzleNav .puzzle-toolbar-setup {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    width: 100%;
  }
  #puzzleNav .puzzle-toolbar-setup .puzzle-toolbar-form {
    display: contents !important;
  }
  #puzzleNav .puzzle-toolbar-setup .puzzle-toolbar-select,
  #puzzleNav .puzzle-toolbar-setup .puzzle-toolbar-select-mode,
  #puzzleNav .puzzle-toolbar-setup .puzzle-toolbar-select-difficulty {
    width: 100%;
    min-width: 0;
    min-height: 48px;
    max-width: 100%;
    height: auto;
    box-sizing: border-box;
    font-size: 1rem;
    /* Full-width on mobile -- left-align the label to match the Helpers/More
       buttons instead of the desktop toolbar's centered text. */
    text-align: left;
    text-align-last: left;
  }
  /* Helpers: 2×2 grid of tool buttons. !important beats the base
     .puzzle-toolbar-group { display: inline-flex } rule that appears
     later in the file at equal specificity. */
  #puzzleNav .puzzle-toolbar-tools {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    width: 100%;
  }
  #puzzleNav .puzzle-toolbar-tools .puzzle-tool-button {
    width: 100%;
    justify-content: flex-start;
    min-height: 48px;
    font-size: 1rem;
  }
  /* The four Helpers buttons carry tool-priority-N classes that the desktop
     progressive-overflow rules hide (display:none !important) at narrow widths.
     In the expanded mobile sheet that would leave the Helpers grid empty, so
     re-show them here -- this sheet is where they're meant to live. */
  #puzzleNav .puzzle-toolbar-surface.show .puzzle-toolbar-tools .puzzle-tool-button {
    display: flex !important;
  }
  /* ...and hide their now-redundant overflow duplicates in the More list so
     the tools don't appear twice in the sheet. The real More-only items
     (Shadow, Restart, Save, Embed) are not .tool-overflow, so they stay. */
  #puzzleNav .puzzle-toolbar-surface.show .puzzle-toolbar-more .dropdown-item.tool-overflow {
    display: none !important;
  }
  /* More: inline the dropdown items as a 2-col grid (no popover) to match the
     Helpers grid above and save vertical space. */
  #puzzleNav .puzzle-toolbar-more {
    width: 100%;
  }
  #puzzleNav .puzzle-toolbar-more #dropdownMore {
    display: none;
  }
  #puzzleNav .puzzle-toolbar-more .dropdown-menu {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    position: static !important;
    transform: none !important;
    border: none !important;
    box-shadow: none !important;
    background: transparent !important;
    padding: 0 !important;
    margin: 0 !important;
    width: 100%;
    float: none;
    min-width: 0;
    opacity: 1 !important;
    visibility: visible !important;
    /* The desktop fade rule sets pointer-events: none on the unopened
       dropdown. On mobile we render it inline, so re-enable input. */
    pointer-events: auto !important;
  }
  /* The background picker lives inside the More dropdown but is not a tool
     button -- span it across both grid columns so it isn't squeezed into a
     single 2-col cell. */
  #puzzleNav .puzzle-toolbar-more .dropdown-menu .puzzle-bg-section {
    grid-column: 1 / -1;
  }
  /* Match the Helpers pill-card look: bordered, rounded, no list dividers. */
  #puzzleNav .puzzle-toolbar-more .dropdown-item {
    padding: 0 1rem;
    border: 1px solid var(--hairline);
    border-radius: 12px;
    background: var(--surface, #fffdf8);
    min-height: 48px;
    display: flex;
    align-items: center;
    font-size: 1rem;
    color: var(--ink);
  }
  #puzzleNav .puzzle-toolbar-more .dropdown-item:hover,
  #puzzleNav .puzzle-toolbar-more .dropdown-item:focus {
    background: rgba(222, 213, 201, 0.32);
  }
  /* Hide the tool-overflow duplicates on mobile — those exist for the
     narrow-desktop progressive collapse. The Helpers section already
     shows Fullscreen/Edges/Arrange/Preview, so they'd duplicate here. */
  #puzzleNav .puzzle-toolbar-more .dropdown-item.tool-overflow {
    display: none !important;
  }
  /* Background section is rendered by JS inside the dropdown — give it
     room to breathe and make sure its own swatches/tabs receive taps. */
  #puzzleNav .puzzle-toolbar-more .puzzle-bg-section {
    border-top: 1px solid var(--hairline);
    margin-top: 0.5rem;
    padding: 1rem 0 0;
    min-width: 0;
    pointer-events: auto;
  }
  #puzzleNav .puzzle-toolbar-more .puzzle-bg-section * {
    pointer-events: auto;
  }
  /* Timer's outer position on mobile — sits inline with Menu pill */
  #puzzleNav .puzzle-toolbar-timer-outer {
    padding-right: 0;
  }
  /* "Done" button — pinned to the bottom of the sheet (sticky so it's
     always reachable without scrolling up to the Options pill). Tapping
     toggles the same collapse, closing the menu. */
  #puzzleNav .puzzle-toolbar-done {
    position: sticky;
    bottom: 0;
    margin-top: 1.5rem;
    width: 100%;
    min-height: 52px;
    padding: 0.85rem 1rem;
    border: none;
    border-radius: 12px;
    background: var(--ink, #1a1a1a);
    color: #fff;
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    cursor: pointer;
    box-shadow: 0 -8px 16px -10px rgba(0, 0, 0, 0.18);
    transition: background 0.15s ease, transform 0.1s ease;
  }
  #puzzleNav .puzzle-toolbar-done:hover,
  #puzzleNav .puzzle-toolbar-done:focus {
    background: #000;
  }
  #puzzleNav .puzzle-toolbar-done:active {
    transform: scale(0.98);
  }
}
/* Hide the Done button outside the mobile sheet (desktop never sees it). */
#puzzleNav .puzzle-toolbar-done {
  display: none;
}
@media (max-width: 767.98px) {
  #puzzleNav .puzzle-toolbar-surface.show .puzzle-toolbar-done,
  #puzzleNav .puzzle-toolbar-surface.collapsing .puzzle-toolbar-done {
    display: block;
  }
}

/* Progressive overflow: as the viewport narrows, tool buttons collapse
   into the More dropdown one-by-one in reverse priority order
   (Fullscreen → Edges → Arrange → Preview) so the toolbar never wraps. */
#puzzleNav .puzzle-toolbar-more .dropdown-item.tool-overflow {
  display: none;
}
/* Force the desktop toolbar to never wrap — progressive overflow is the
   only escape valve. Without this, awkward in-between widths can wrap a
   second row before the priority breakpoints fire. */
@media (min-width: 768px) {
  #puzzleNav .puzzle-toolbar-surface,
  #puzzleNav .puzzle-toolbar-group {
    flex-wrap: nowrap;
  }
}

/* Breakpoints tuned to actual button widths. These need to be set
   GENEROUSLY HIGH because the toolbar contains the Options-pill width,
   timer group, two selects, four tool buttons + More + breadcrumbs row. */
/* !important needed because Fullscreen button carries Bootstrap's .show
   class (display: block !important) which would otherwise outweigh these
   priority hides. */
@media (max-width: 1023.98px) {
  #puzzleNav .tool-priority-1 { display: none !important; }
  #puzzleNav .puzzle-toolbar-more .dropdown-item.tool-overflow-1 { display: flex; }
}
@media (max-width: 939.98px) {
  #puzzleNav .tool-priority-2 { display: none !important; }
  #puzzleNav .puzzle-toolbar-more .dropdown-item.tool-overflow-2 { display: flex; }
}
@media (max-width: 859.98px) {
  #puzzleNav .tool-priority-3 { display: none !important; }
  #puzzleNav .puzzle-toolbar-more .dropdown-item.tool-overflow-3 { display: flex; }
}
@media (max-width: 799.98px) {
  #puzzleNav .tool-priority-4 { display: none !important; }
  #puzzleNav .puzzle-toolbar-more .dropdown-item.tool-overflow-4 { display: flex; }
}

/* Compact the setup selects at narrow desktop widths so Style + Difficulty
   take less horizontal room before they get pushed into the Options sheet
   at the md breakpoint. Pairs with the bumped overflow breakpoints above. */
@media (min-width: 768px) and (max-width: 1199.98px) {
  #puzzleNav .puzzle-toolbar-select {
    min-width: 0;
    padding-left: 0.55rem;
    padding-right: 1.35rem;
    background-position: calc(100% - 5px) 50%;
    font-size: 0.78rem;
  }
  #puzzleNav .puzzle-toolbar-select-mode { min-width: 76px; }
  #puzzleNav .puzzle-toolbar-select-difficulty { min-width: 118px; }
  #puzzleNav .puzzle-tool-button {
    padding: 0.28rem 0.55rem;
    gap: 0.3rem;
  }
  #puzzleNav .puzzle-toolbar-surface { gap: 0.35rem; }
  #puzzleNav .puzzle-toolbar-group { gap: 0.3rem; }
}

.puzzle-page-heading {
  min-width: 0;
}

.puzzle-page-title {
  font-family: "Nunito Sans", sans-serif;
  font-size: clamp(1rem, 0.94rem + 0.22vw, 1.18rem);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--ink);
}

.puzzle-page-meta {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 0.45rem;
  color: var(--muted);
  font-size: 0.9rem;
  font-weight: 700;
  white-space: nowrap;
}

.puzzle-stat {
  color: var(--ink);
  opacity: 0.82;
}

#timer.puzzle-timer {
  font-variant-numeric: tabular-nums;
  display: inline-block;
}

.puzzle-timer-group {
  display: inline-flex;
  align-items: center;
  gap: 0.1rem;
}

.puzzle-timer-control {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--ink);
  border-radius: 8px;
  cursor: pointer;
  opacity: 0.78;
  transition: opacity 0.12s ease, background 0.12s ease;
}
/* The eye+digits button: wider, with the digits sitting next to the icon. */
.puzzle-timer-display {
  gap: 0.4rem;
  /* Right padding is heavier than left because the eye SVG has internal
     whitespace inside its viewBox, while the digits end flush at their box
     edge. The asymmetric padding makes the two sides look optically equal. */
  padding: 0 0.95rem 0 0.6rem;
  font: inherit;
  font-weight: 700;
  color: var(--ink);
}
.puzzle-timer-display #timer {
  text-align: left;
  opacity: 1;
  color: var(--ink);
}
.puzzle-timer-control:hover {
  opacity: 1;
  background: rgba(222, 213, 201, 0.4);
}
/* Dark mode — the brand cream wash blooms way too bright on the
   dark canvas surround. Drop to the same subtle white tint used by
   the nav links for consistency. */
:root[data-theme="dark"] .puzzle-timer-control:hover {
  background: rgba(255, 255, 255, 0.06);
}
.puzzle-timer-control:focus {
  outline: none;
}
/* Keyboard focus gets a subtle ring; mouse click does not. */
.puzzle-timer-control:focus-visible {
  outline: 2px solid var(--accent, #2d4f55);
  outline-offset: 1px;
}
.puzzle-timer-icon {
  width: 16px;
  height: 16px;
}
/* The play triangle reads visually heavier than the pause bars at the same
   bounding box. Trim it ~10% so the two states feel balanced. */
.puzzle-timer-icon--play {
  width: 14px;
  height: 14px;
}

/* On mobile, the play/pause + eye icons live in the always-visible outer
   timer strip. Make them genuinely tappable (44x44) and visually heftier so
   they don't read as decorative. */
@media (max-width: 767.98px) {
  .puzzle-timer-control {
    min-width: 44px;
    min-height: 44px;
    border-radius: 10px;
    opacity: 0.9;
  }
  .puzzle-timer-display {
    padding: 0 1.05rem 0 0.75rem;
    font-size: 1.05rem;
  }
  .puzzle-timer-icon {
    width: 22px;
    height: 22px;
  }
  .puzzle-timer-icon--play {
    width: 19px;
    height: 19px;
  }
}
/* Toggle which icon shows based on aria-pressed. Defaults: pause + eye. */
.puzzle-timer-icon--play,
.puzzle-timer-icon--eye-slash { display: none; }
#pauseToggle[aria-pressed="true"] .puzzle-timer-icon--pause { display: none; }
#pauseToggle[aria-pressed="true"] .puzzle-timer-icon--play { display: inline-block; }
#timerVisToggle[aria-pressed="true"] .puzzle-timer-icon--eye { display: none; }
#timerVisToggle[aria-pressed="true"] .puzzle-timer-icon--eye-slash { display: inline-block; }
/* Numeric timer fades out when hidden, in when shown. */
.puzzle-timer-group #timer {
  opacity: 1;
  transition: opacity 0.18s ease;
}
.puzzle-timer-group:has(#timerVisToggle[aria-pressed="true"]) #timer {
  opacity: 0;
}

/* Smooth fade for the More-menu dropdown. Bootstrap toggles .show on
   .dropdown-menu; we layer opacity + a tiny translate on top of its
   display switch by using a transition delay on visibility. */
.puzzle-game-toolbar .dropdown-menu {
  display: block;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s linear 0.16s;
}
.puzzle-game-toolbar .dropdown-menu.show {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  pointer-events: auto;
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0s;
}

/* Paused state — hide the canvas pieces and show a centered overlay so
   someone stepping away can't peek. */
#pausedOverlay {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 5;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
/* Big circular resume button — inspired by Sumplete's pause/play pattern.
   The button itself receives clicks (overlay pointer-events stays off so
   the rest of the canvas area isn't blocked when resume fires). */
.paused-resume-btn {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  border: 10px solid #fff;
  background: var(--accent-amber);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  pointer-events: auto;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
  transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}
.paused-resume-btn svg {
  width: 38px;
  height: 38px;
  transform: translateX(2px); /* nudge play triangle so it looks centered */
}
.paused-resume-btn:hover {
  transform: scale(1.08);
  background: var(--accent-amber-soft);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.34);
}
.paused-resume-btn:active {
  transform: scale(0.96);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.22);
}
.paused-resume-btn:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 4px;
}
/* Canvas fades out when paused — pieces ease away rather than snap. */
#myCanvas {
  transition: opacity 0.35s ease;
}
body:has(#pauseToggle[aria-pressed="true"]) #myCanvas {
  opacity: 0;
  pointer-events: none;
}
body:has(#pauseToggle[aria-pressed="true"]) #pausedOverlay {
  display: flex;
}
/* Overlay fades in just after the canvas finishes fading out. */
#pausedOverlay {
  opacity: 0;
  transition: opacity 0.25s ease 0.15s;
}
body:has(#pauseToggle[aria-pressed="true"]) #pausedOverlay {
  opacity: 1;
}
/* Ensure overlay positions relative to the canvas container. */
#canvasContainer {
  position: relative;
}
/* On mobile, the canvas can be taller than the visible viewport. If we
   flex-center inside #canvasContainer the button lands at the geometric
   middle of the canvas, which is often offscreen. Instead: align to the
   top of the overlay and make the button itself position:sticky so it
   stays at viewport vertical center as long as the canvas occupies the
   screen — then naturally scrolls away with the canvas once you scroll
   past its bottom edge. */
@media (max-width: 767.98px) {
  #pausedOverlay {
    align-items: flex-start;
  }
  .paused-resume-btn {
    position: sticky;
    /* 96px button + 10px border = 116px tall; half ≈ 58px */
    top: calc(50vh - 58px);
    transition: opacity 0.18s ease, transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
  }
  /* When the Options sheet is open, the resume button would float on top
     of the setup/helpers controls. Fade it out so the menu reads cleanly;
     it returns the moment the sheet closes. */
  body:has(#collapsePuzzleMenu.show, #collapsePuzzleMenu.collapsing) .paused-resume-btn {
    opacity: 0;
    pointer-events: none;
  }
}

.puzzle-secondary-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-height: 32px;
  padding: 0.28rem 0.65rem;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font-weight: 800;
  line-height: 1.1;
  box-shadow: 0 1px 2px rgba(38, 30, 21, 0.05);
}

.puzzle-secondary-action-icon {
  width: 15px;
  height: 15px;
  flex: none;
}

.puzzle-secondary-action:hover,
.puzzle-secondary-action:focus {
  background: rgba(222, 213, 201, 0.34);
  color: var(--ink);
  text-decoration: none;
}

/* Reddit-style toggle: liked state fills the button with the accent color. */
.puzzle-like-button[aria-pressed="true"] {
  background: var(--ink, #1a1a1a);
  color: #fff;
  border-color: var(--ink, #1a1a1a);
}
.puzzle-like-button[aria-pressed="true"] .puzzle-secondary-action-icon path {
  fill: currentColor;
}
.puzzle-like-button[aria-pressed="true"]:hover,
.puzzle-like-button[aria-pressed="true"]:focus {
  background: var(--ink, #1a1a1a);
  color: #fff;
  opacity: 0.9;
}

#puzzleNav.puzzle-game-toolbar {
  padding: 0.25rem 0.5rem 0.35rem;
}

#puzzleNav .puzzle-toolbar-navbar {
  justify-content: normal;
  padding: 0;
}

/* On desktop, push the pause + timer group to the right edge of the
   toolbar via flex order + auto-margin. Toolbar content sits left, timer
   group anchors right. Mobile keeps the timer in its original spot
   (next to the Options pill) so it stays visible without opening the sheet. */
@media (min-width: 768px) {
  #puzzleNav .puzzle-toolbar-surface {
    order: 1;
    /* Don't let the collapse stretch — otherwise margin-left:auto on the
       timer has nowhere to push from. */
    flex: 0 0 auto;
    width: auto;
  }
  #puzzleNav .puzzle-toolbar-timer-outer {
    order: 2;
    margin-left: auto;
    /* Guarantee a visible breathing gap even at narrow desktop widths. */
    padding-left: 1.5rem;
  }
}

/* Options pill is only meaningful on mobile (where it toggles the sheet).
   On desktop the menu items are inline, so hide the toggler. */
@media (max-width: 767.98px) {
  #puzzleNav .puzzle-toggler {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    min-height: 34px;
    padding: 0.25rem 0.6rem;
    border-radius: 8px !important;
    background: var(--surface);
    font-weight: 800;
  }
}
@media (min-width: 768px) {
  #puzzleNav .puzzle-toggler { display: none !important; }
}
#puzzleNav .puzzle-toggler-chevron {
  width: 12px;
  height: 12px;
  opacity: 0.75;
  transition: transform 0.18s ease, opacity 0.18s ease;
  flex: none;
}
#puzzleNav .puzzle-toggler[aria-expanded="true"] .puzzle-toggler-chevron {
  transform: rotate(180deg);
  opacity: 1;
}

#puzzleNav .puzzle-toolbar-surface {
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem;
  padding: 0;
  border: none;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}

#puzzleNav .puzzle-toolbar-surface.show {
  display: flex;
}

#puzzleNav .puzzle-toolbar-group {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.35rem;
}

#puzzleNav .puzzle-toolbar-form {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
}

#puzzleNav .puzzle-toolbar-select {
  width: auto;
  min-width: 92px;
  height: 30px;
  padding: 0.2rem 1.5rem 0.2rem 0.85rem;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  background-color: var(--surface);
  background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4.25 6.25L8 10L11.75 6.25' stroke='%236F706D' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-position: calc(100% - 7px) 50%;
  background-size: 14px 14px;
  background-repeat: no-repeat;
  color: var(--ink);
  font-size: 0.8rem;
  font-weight: 600;
  text-align: center;
  text-align-last: center;
  line-height: 1.2;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  box-shadow: 0 1px 2px rgba(38, 30, 21, 0.05);
  transition: border-color 0.14s ease, box-shadow 0.14s ease, background-color 0.14s ease;
}

#puzzleNav .puzzle-toolbar-select-mode {
  min-width: 86px;
}

#puzzleNav .puzzle-toolbar-select-difficulty {
  min-width: 150px;
}

#puzzleNav .puzzle-toolbar-select:hover {
  border-color: #bcb2a4;
  /* Hover bg flips to a fixed light fill, so the text needs to be
     pinned dark — otherwise the dark-mode --ink (off-white) renders
     as invisible white-on-white. */
  background-color: #fff;
  color: #191817;
}

/* In dark mode the white select pill (and its even-brighter white
   hover) reads as a stark cutout against the dark page. Lift it to
   the same warm-near-black surface used by other dark-mode controls
   so it feels like part of the toolbar. */
:root[data-theme="dark"] #puzzleNav .puzzle-toolbar-select {
  background-color: #2a231d;
  color: var(--ink);
  border-color: var(--hairline);
}
:root[data-theme="dark"] #puzzleNav .puzzle-toolbar-select:hover {
  background-color: #332a23;
  color: var(--ink);
  border-color: rgba(255, 255, 255, 0.18);
}
:root[data-theme="dark"] #puzzleNav .puzzle-toolbar-select:focus {
  background-color: #332a23;
  color: var(--ink);
  border-color: var(--nooksky);
  box-shadow: 0 0 0 3px rgba(143, 205, 219, 0.18);
}

#puzzleNav .puzzle-toolbar-select:focus {
  border-color: var(--nooksky);
  box-shadow: 0 0 0 3px rgba(143, 205, 219, 0.28);
  outline: none;
}

#puzzleNav .puzzle-tool-button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 30px;
  padding: 0.28rem 0.65rem;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  font-size: 0.8rem;
  font-weight: 700;
  line-height: 1.1;
  box-shadow: 0 1px 2px rgba(38, 30, 21, 0.05);
  transition: background-color 0.14s ease, border-color 0.14s ease, transform 0.14s ease;
}

#puzzleNav .puzzle-tool-icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: inherit;
  transform: translateY(-1px);
}

#puzzleNav .puzzle-tool-button:hover,
#puzzleNav .puzzle-tool-button:focus,
#puzzleNav .show > .puzzle-tool-button.dropdown-toggle {
  background: rgba(155, 222, 216, 0.45);
  border-color: rgba(95, 185, 177, 0.55);
  /* Hover fill (mint pastel) stays light in both themes — pin text
     to a fixed dark so the label stays legible. */
  color: #191817;
  transform: translateY(-1px);
}

#puzzleNav .puzzle-tool-button.active,
#puzzleNav .puzzle-tool-button:active {
  background: var(--mirthtile);
  border-color: var(--mirthtile-deep);
  color: #191817;
}

/* Toggle highlight for More-section toggles that are dropdown-items rather than
   tool-buttons (e.g. Overlay/Shadow). Mirrors the .puzzle-tool-button.active
   mint highlight and overrides Bootstrap's default blue .dropdown-item.active
   so an "on" toggle reads as lit -- the user reopens the menu and sees it's
   active before toggling it off. */
#puzzleNav .puzzle-toolbar-more .dropdown-item.active {
  background: var(--mirthtile);
  border-color: var(--mirthtile-deep);
  color: #191817;
}

#puzzleNav .puzzle-toolbar-more .dropdown-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

#puzzleNav .puzzle-toolbar-more .dropdown-toggle::after {
  display: none;
}

#puzzleNav .puzzle-toolbar-more .dropdown-menu {
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 0.35rem;
  background: var(--surface);
  box-shadow: 0 12px 28px rgba(38, 30, 21, 0.14);
}

#puzzleNav .puzzle-toolbar-more .dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  /* Match horizontal padding to the BACKGROUND section below so icons
     align flush-left with the section label. */
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  border-radius: 7px;
  color: var(--ink);
  font-weight: 700;
}

#puzzleNav .puzzle-dropdown-icon {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--muted);
}

/* Mute toggle: show whichever icon matches the current state. The
   button starts in `.is-muted` (the puzzle is muted by default), so the
   slashed-speaker icon is what the user sees on first open. Explicit
   display rules on BOTH icons so neither relies on browser defaults. */
#puzzleNav .muteButton .puzzle-dropdown-icon--unmute { display: inline-block; }
#puzzleNav .muteButton .puzzle-dropdown-icon--mute { display: none; }
#puzzleNav .muteButton.is-muted .puzzle-dropdown-icon--unmute { display: none; }
#puzzleNav .muteButton.is-muted .puzzle-dropdown-icon--mute { display: inline-block; }

#puzzleNav .puzzle-toolbar-more .dropdown-item:hover .puzzle-dropdown-icon,
#puzzleNav .puzzle-toolbar-more .dropdown-item:focus .puzzle-dropdown-icon {
  color: var(--ink);
}

#puzzleNav .puzzle-toolbar-more .dropdown-item:hover,
#puzzleNav .puzzle-toolbar-more .dropdown-item:focus {
  background: rgba(222, 213, 201, 0.42);
  color: var(--ink);
}

#puzzleNav .puzzle-partner-logo {
  margin-right: 0.45rem;
}

#info-box {
  text-transform: capitalize;
  color: gray;
  font-weight: bold;
  top: 3px;
  position: relative;
  font-size: 0.75em;
}

#puzzleOverlay,
#partnerOverlay {
  position: absolute;
  top: 0px;
  left: 0px;
  background-color: #ffffff;
  width: 100vw;
  height: 100vh;
  z-index: 9999;
}

#partnerOverlay {
  z-index: 10000;
}

#partnerOverlayInner {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

#puzzleOverlayInner {
  text-align: center;
  padding: 50px 20px 0px 20px;
}

.animate-loading-bar {
  animation-duration: 3s;
  animation-name: progression;
  animation-iteration-count: 1;
}

@keyframes progression {
  from {
    width: 0%;
  }

  to {
    width: 100%;
  }
}

.partner-logo-animate {
  animation: pulse 1s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

@keyframes pulse {
  0% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }

  50% {
    -webkit-transform: scale(0.8);
    transform: scale(0.8);
  }

  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
}

#adSidebarContainer {
  flex: 0 0 300px;
  height: 120vh;
  overflow-x: hidden;
}

#adSidebarContainer #imapuzzle_desktop_right_rail_2 {
  /* width: 100%; */
}

#imapuzzle_D_2 {
  width: 970px;
  height: 250px;
}

#createContainer #thumbnail {
  max-height: 100px;
}

.account-puzzle-options .badge,
.account-puzzle-options .btn {
  font-size: 0.7em;
}

@media (max-width: 1018px) {
  #adSidebarContainer {
    flex: 0 0 300px;
  }

  #adSidebarContainer #imapuzzle_desktop_right_rail_2 {
  }
}

@media (max-width: 919px) {
  #adSidebarContainer {
    flex: 0 0 160px;
  }

  #adSidebarContainer #imapuzzle_desktop_right_rail_2 {
    /* width: 160px; */
  }

  #imapuzzle_D_2 {
    width: 100%;
    height: 250px;
  }
}

@media (max-width: 770px) {
  #adSidebarContainer {
    display: none;
  }

  #adSidebarContainer {
    display: none;
  }

  #adSidebarContainer ins {
    display: none;
  }

  svg.play-puzzle {
    right: -4px;
    transform: rotate(35deg) scale(1.1);
    z-index: 1;
  }

  .play-label {
    right: 6px;
  }
}

@media (max-width: 769px) {
  #adSidebarContainer {
    display: none;
  }

  #adSidebarContainer ins {
    display: none;
  }
}

/* Narrow desktop / tablet range — the nav is just barely big enough to
   show all items expanded (Bootstrap kicks expand at 768px). We force
   the navbar to a single row, shrink the logo, tighten paddings, narrow
   the search, and drop the Sign in icon so everything fits one line. */
@media (min-width: 768px) and (max-width: 936px) {
  #site-header.navbar {
    flex-wrap: nowrap;
  }
  #site-header .navbar-collapse {
    flex-wrap: nowrap;
  }
  #site-header .navbar-nav {
    flex-wrap: nowrap;
  }
  #site-header .navbar-brand.main-logo {
    flex: 0 0 auto;
    margin-right: 0.5rem;
  }
  #site-header .navbar-brand.main-logo img {
    width: 110px;
    height: auto;
  }
  #site-header .navbar-brand.main-logo .main-logo-svg {
    width: 110px;
    height: auto;
  }
  #site-header .navbar-nav .nav-link {
    padding: 0.4rem 0.45rem;
    font-size: 0.92rem;
    white-space: nowrap;
  }
  #site-header .nav-categories-link {
    gap: 0.2rem;
  }
  #site-header .nav-search.ml-md-4 {
    margin-left: 0.45rem !important;
    margin-right: 0.35rem !important;
    width: 140px;
    flex: 0 0 auto;
    padding-left: 12px;
    padding-right: 2px;
  }
  #site-header .nav-search-input {
    font-size: 0.86rem;
    padding: 6px 4px 6px 0;
  }
  #site-header .nav-search-btn {
    width: 30px;
    height: 30px;
  }
  #site-header .nav-search-btn svg {
    width: 14px;
    height: 14px;
  }
  /* Sign in: text-only at this width to save space. */
  #site-header .nav-signin-link {
    gap: 0;
    white-space: nowrap;
    padding: 0.4rem 0.65rem;
  }
  #site-header .nav-signin-icon {
    display: none;
  }
}

@media (max-width: 420px) {
  .navbar-brand.main-logo .main-logo-svg {
    width: 100px;
    height: auto;
  }
  .navbar-brand.main-logo img {
    width: 100px;
    height: 20px;
  }

  #adSidebarContainerMobile {
    display: block !important;
    position: absolute;
    bottom: 5px;
    width: 300px;
    text-align: center;
    left: 50%;
    transform: translate(-50%, 0%);
  }

  #myCanvas {
    height: -moz-calc(100% - 250px);
    height: -webkit-calc(100% - 250px);
    height: -o-calc(100% - 250px);
    height: calc(80vh - 250px);
    min-height: calc(80vh - 250px);
  }

  #congratsRelatedRow .col {
    flex: 0 0 33%;
    max-width: 33%;
    padding-left: 2px;
    padding-right: 2px;
  }
}

@media (max-height: 400px) {
  .gallery,
  .gallery-feature {
    height: 60vh;
  }
}

/* ===== Homepage hero ===== */
.home-hero {
  display: flex;
  align-items: center;
  gap: 2.5rem;
  margin: 1rem 0 2rem;
}

.home-hero-text {
  flex: 1 1 0;
  min-width: 0;
}

.home-hero-title {
  font-family: "Nunito Sans", sans-serif;
  font-size: clamp(2rem, 4.5vw, 3.25rem);
  font-weight: 900;
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin-bottom: 0.75rem;
}

.home-hero-title-sub {
  display: block;
  margin-top: 10px;
  font-size: clamp(1rem, 1.8vw, 1.35rem);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.3;
  color: var(--ink);
  opacity: 0.62;
}

.home-hero-tagline {
  font-size: 1.15rem;
  line-height: 1.55;
  color: var(--muted);
  max-width: 30ch;
  margin-bottom: 1.5rem;
}

.home-hero-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* ===== Shared primary CTA — mint variant of the brand CTA style =====
   Same physics as the homepage PLAY TODAY'S PUZZLE button (chunky black
   border + offset black drop shadow) but in mint instead of amber. Use
   this class for any "this is the main action on this surface" button
   (PLAY THIS PUZZLE, SAVE in the quiz form, etc.). Pair with .btn-block
   or set width separately for layout. */
.btn.btn-mint-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 54px;
  padding: 0.82rem 1.55rem;
  background: var(--mirthtile);
  color: #000;
  border: 3px solid #000;
  border-radius: 12px;
  font-weight: 800;
  font-size: 14px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.1;
  box-shadow: 3px 3px 0 0 #000;
  cursor: pointer;
  transition: background-color 0.12s ease, transform 0.12s ease, box-shadow 0.12s ease;
}

.btn.btn-mint-primary:hover,
.btn.btn-mint-primary:focus {
  background: var(--mirthtile-soft);
  color: #000;
  text-decoration: none;
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 0 #000;
}

.btn.btn-mint-primary:active {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 0 #000;
}

.btn.btn-mint-primary svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.home-hero-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 54px;
  padding: 0.82rem 1.55rem;
  /* Border + shadow stay black in both themes — these CTAs are
     designed around the chunky black outline + drop shadow as a
     deliberate brand element. */
  border: 3px solid #000;
  font-weight: 800;
  font-size: 14px;
  border-radius: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.1;
}

.home-hero-start-btn {
  gap: 12px;
  background: var(--accent-amber);
  /* Yellow background needs dark text in both themes for legibility. */
  color: #000;
  box-shadow: 3px 3px 0 0 #000;
  transition: transform 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
}

.home-hero-start-btn:hover,
.home-hero-start-btn:focus {
  background: var(--accent-amber-soft);
  color: #000;
  text-decoration: none;
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 0 #000;
}

.home-hero-start-btn:active {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 0 #000;
}

/* Dark mode collapses --accent-amber onto the soft variant, so the
   light/hover pair becomes identical and the hover feedback vanishes.
   Bump the hover a step brighter so it still pops. */
:root[data-theme="dark"] .home-hero-start-btn:hover,
:root[data-theme="dark"] .home-hero-start-btn:focus {
  background: #ffd96a;
}

.home-hero-start-btn svg {
  width: 21px;
  height: 21px;
  flex: none;
}

/* The make-puzzle "Play this puzzle" CTA reuses the home hero style — but as
   a button (not anchor) inside a block-flex container. Override btn-block
   so the styled width/padding/border still apply. */
.create-play-btn.btn-block {
  width: auto;
  display: inline-flex !important;
  margin-bottom: 0.6rem;
}

.home-hero-cta .btn-outline-success {
  background: var(--surface);
  color: var(--ink);
  /* Pin shadow to black to match the primary CTA's brand outline style. */
  box-shadow: 3px 3px 0 0 #000;
  transition: transform 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
}

.home-hero-cta .btn-outline-success:hover,
.home-hero-cta .btn-outline-success:focus {
  border-color: #000;
  /* Keep the same fill + text color as the base state — no reversal on
     hover. The transform + shadow alone communicate the lift. */
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 0 #000;
}

/* In dark mode the secondary CTA's surface comes in a touch too close
   to the page bg; lift it a step so the button reads as a clear
   surface against the background. Hover holds the same fill — the
   transform/shadow does the work. */
:root[data-theme="dark"] .home-hero-cta .btn-outline-success {
  background: #2a231d;
}
:root[data-theme="dark"] .home-hero-cta .btn-outline-success:hover,
:root[data-theme="dark"] .home-hero-cta .btn-outline-success:focus {
  background: #2a231d;
}

/* Bootstrap-override (line ~281) targets
   `.btn-outline-success:not(:disabled):not(.disabled):active` (0-4-0) and
   paints the button mint with white text. Match that selector here so
   the home-hero rule wins; keep the base fill + ink text. */
.home-hero-cta .btn-outline-success:not(:disabled):not(.disabled):active,
.home-hero-cta .btn-outline-success:not(:disabled):not(.disabled).active {
  background-color: var(--surface);
  border-color: #000;
  color: var(--ink);
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 0 #000;
}

:root[data-theme="dark"] .home-hero-cta .btn-outline-success:not(:disabled):not(.disabled):active,
:root[data-theme="dark"] .home-hero-cta .btn-outline-success:not(:disabled):not(.disabled).active {
  background-color: #2a231d;
}

.home-hero-feature {
  flex: 0 0 42%;
  position: relative;
  cursor: pointer;
  color: var(--ink);
  text-decoration: none;
}

.home-hero-feature:hover,
.home-hero-feature:focus {
  color: var(--ink);
  text-decoration: none;
}

.home-hero-feature .gallery-feature {
  margin-top: 0;
}

.home-hero-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  /* Pure black pill with white text — sits over the image area in
     both themes, so the color stays fixed. */
  background: #000;
  color: #fff;
  font-family: "Nunito Sans", sans-serif;
  font-weight: 900;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 5px 14px;
  border-radius: 6px;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25);
}

.home-hero-feature-meta {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 12px 16px 14px;
  /* Use the surface token so the strip flips with the theme and the
     title (which uses --ink) keeps proper contrast. */
  background: var(--surface);
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  transition: transform 0.14s ease-out, box-shadow 0.14s ease-out;
}

.home-hero-feature .gallery-feature {
  transition: transform 0.14s ease-out;
}

@media (hover: hover) {
  .home-hero-feature:hover .gallery-feature,
  .home-hero-feature:hover .home-hero-feature-meta {
    transform: translateY(-4px);
  }
  .home-hero-feature:hover .home-hero-feature-meta {
    box-shadow: 0 14px 14px -12px rgba(0, 0, 0, 0.22);
  }
}

.home-hero-feature-title {
  min-width: 0;
  color: var(--ink);
  font-weight: 800;
  font-size: 1rem;
  line-height: 1.25;
}

.home-hero-feature-stats {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex: none;
  color: var(--muted);
  font-size: 0.82rem;
  font-weight: 800;
}

.home-hero-feature-stat {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

.home-hero-feature-stat svg {
  width: 14px;
  height: 14px;
}

.section-heading {
  display: inline-block;
  font-weight: 800;
  font-size: 1.65rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  border-bottom: 4px solid var(--mirthtile);
  padding-bottom: 2px;
  margin-top: 2.5rem;
  margin-bottom: 1rem;
}

@media (max-width: 767px) {
  .home-hero {
    flex-direction: column;
    align-items: stretch;
    gap: 1.5rem;
    margin: 0.5rem 0 1.75rem;
  }

  .home-hero-text {
    order: 2;
  }

  .home-hero-feature {
    order: 1;
    flex: 1 1 auto;
  }

  .home-hero-tagline {
    max-width: none;
  }

  .home-hero-btn {
    flex: 1 1 auto;
    text-align: center;
  }

  .home-hero-feature-meta {
    align-items: flex-start;
  }
}

@media (max-width: 420px) {
  .home-hero-feature-meta {
    flex-direction: column;
    gap: 0.35rem;
  }

  .home-hero-feature-stats {
    align-self: flex-start;
  }
}

/* Make-puzzle page header */
.make-puzzle-title {
  color: var(--ink);
  font-size: 28px;
  font-weight: 500;
  margin-bottom: 0.3rem;
}
.make-puzzle-intro {
  font-size: 1.05rem;
  color: #636e72;
  margin-bottom: 0.5rem;
  line-height: 1.55;
}

/* Make-puzzle upload dropzone */
#createContainer {
  margin-top: 0.5rem;
}

.upload-dropzone {
  border: 2px dashed #b8deda;
  /* Tighter than the parent card (22px) so the curves feel like
     concentric arcs — outer wraps inner with visible breathing room. */
  border-radius: 12px;
  background: #f6fbf7;
  padding: 3rem 2rem;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
}
.upload-dropzone:hover {
  border-color: var(--mirthtile);
  background: #eef9f7;
  box-shadow: 0 0 0 4px rgba(155, 222, 216, 0.24);
}
.upload-dropzone.drag-over {
  border-color: var(--mirthtile);
  background: #e1f4f1;
  box-shadow: 0 0 0 4px rgba(155, 222, 216, 0.34);
}

.upload-dropzone-inner {
  pointer-events: none;
}

.upload-icon {
  color: var(--mirthtile-deep);
  margin-bottom: 1rem;
  opacity: 0.8;
}
.upload-dropzone:hover .upload-icon {
  opacity: 1;
}

.upload-dropzone-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: #2d3436;
  margin-bottom: 0.5rem;
}

.upload-dropzone-subtitle {
  font-size: 0.95rem;
  color: #636e72;
  margin-bottom: 0.25rem;
}

.upload-browse-link {
  color: var(--nooksky-deep);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.upload-dropzone-formats {
  font-size: 0.8rem;
  color: #b2bec3;
  margin: 0 auto;
  max-width: 42ch;
  letter-spacing: 0.02em;
  text-wrap: balance;
  line-height: 1.45;
}

/* Dark-mode dropzone — deep warm surface with light text, mirroring
   how the rest of the page handles surface inversion. */
:root[data-theme="dark"] .upload-dropzone {
  background: #1a1612;
  border-color: rgba(155, 222, 216, 0.32);
}
:root[data-theme="dark"] .upload-dropzone:hover {
  background: #221d18;
  border-color: var(--mirthtile);
  box-shadow: 0 0 0 4px rgba(155, 222, 216, 0.18);
}
:root[data-theme="dark"] .upload-dropzone.drag-over {
  background: #29241e;
  border-color: var(--mirthtile);
}
:root[data-theme="dark"] .upload-dropzone-title {
  color: var(--ink);
}
:root[data-theme="dark"] .upload-dropzone-subtitle {
  color: var(--muted);
}
:root[data-theme="dark"] .upload-dropzone-formats {
  color: #6b6964;
}
:root[data-theme="dark"] .upload-tos {
  color: var(--muted);
}

.upload-tos {
  font-size: 0.8rem;
  color: #999;
  margin-top: 0.75rem;
  text-align: center;
}
.upload-tos a {
  color: var(--nooksky-deep);
}

@media (max-width: 576px) {
  .upload-dropzone {
    padding: 2rem 1.25rem;
  }
  .upload-dropzone-title {
    font-size: 1.1rem;
  }
}

/* Server-rendered hero image shown before JS puzzle player loads */
.puzzle-hero-image {
  text-align: center;
  padding: 1rem 0;
}

.puzzle-hero-image img {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
}

/* Puzzle meta block — labeled rows (Title / Description / Creator / Tags)
   plus a stats footer (plays · likes · share). Left-aligned at every
   viewport; sits under the canvas. */
/* puzzleBelowCanvas ad slot (300x250 between canvas and meta block):
   give it the same --surface fill as the meta block so the two areas
   flow into each other as one continuous panel below the dark felt.
   Mobile-only -- on desktop the right rail carries the post-canvas
   inventory, so the 300x250 here is redundant. */
.ad-slot[data-ad-placement="puzzleBelowCanvas"] {
  margin: 0;
  padding: 16px 0;
  background-color: var(--surface, #fffdf8);
}

@media (min-width: 768px) {
  .ad-slot[data-ad-placement="puzzleBelowCanvas"] {
    display: none;
  }
}

.puzzle-meta-block {
  background-color: var(--surface, #fffdf8);
  border-top: 1px solid var(--hairline, #ded5c9);
  /* 0.5rem horizontal padding to match the puzzle toolbar above
     (#puzzleNav.puzzle-game-toolbar has padding 0.5rem horizontal). */
  padding: 1.1rem 0.5rem 1.25rem;
  position: relative;
  z-index: 1;
}
.puzzle-meta-block .puzzle-meta-list {
  max-width: 56rem;
}
/* Footer stays unconstrained so its top divider extends the full width
   of the meta block. The inline stats text is short anyway. */
.puzzle-meta-list {
  /* Stacked label-over-value rows at every viewport — reads cleanly and
     keeps the value column at full width for long tag lists. */
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin: 0;
}
.puzzle-meta-row {
  display: block;
}
.puzzle-meta-label {
  display: block;
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  line-height: 1.35;
  margin: 0 0 0.25rem;
}
.puzzle-meta-value {
  margin: 0;
  font-size: 0.95rem;
  line-height: 1.35;
  color: var(--ink);
  min-width: 0;
}
.puzzle-meta-title {
  font-size: 1.05rem;
  font-weight: 700;
}
.puzzle-meta-creator-link {
  color: var(--ink);
  font-weight: 700;
  text-decoration: none;
  border-bottom: 1px solid var(--hairline);
}
.puzzle-meta-creator-link:hover,
.puzzle-meta-creator-link:focus {
  color: var(--ink);
  border-bottom-color: var(--ink);
  text-decoration: none;
}
.puzzle-meta-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
/* Stats footer: plays · likes · share — inline, muted, left-aligned. */
.puzzle-meta-footer {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.55rem;
  margin-top: 1rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--hairline);
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.4;
}
.puzzle-meta-stat,
.puzzle-meta-like,
.puzzle-meta-share {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.puzzle-meta-stat-sep {
  color: var(--hairline);
  user-select: none;
}
.puzzle-meta-like,
.puzzle-meta-share {
  border: none;
  background: transparent;
  padding: 0.25rem 0.4rem;
  margin: 0 -0.4rem;
  font: inherit;
  color: var(--muted);
  border-radius: 6px;
  cursor: pointer;
  transition: color 0.14s ease, background-color 0.14s ease;
}
.puzzle-meta-like:hover,
.puzzle-meta-like:focus,
.puzzle-meta-share:hover,
.puzzle-meta-share:focus {
  color: var(--ink);
  background: rgba(222, 213, 201, 0.32);
  outline: none;
}
.puzzle-meta-like-icon,
.puzzle-meta-share-icon {
  width: 16px;
  height: 16px;
  flex: none;
}
.puzzle-meta-like[aria-pressed="true"] {
  color: #e0413a;
}
.puzzle-meta-like[aria-pressed="true"] .puzzle-meta-like-icon {
  color: #e0413a;
}

/* Related Puzzles section under the meta block — matches the toolbar /
   meta block's 0.5rem horizontal indent. The row's -15px margin and the
   col's +15px padding cancel, so card content lands at 0.5rem from the
   page edge, aligned with the breadcrumb / Options pill / meta labels. */
.related-puzzles-container {
  max-width: none;
  margin-top: 2rem;
  margin-bottom: 2.5rem;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  /* Centers the inline-block .section-heading above the centered row of
     related puzzle cards. The flex row below ignores text-align. */
  text-align: center;
}
.related-puzzles-heading {
  margin-bottom: 1rem;
}


.puzzle-tag-pill {
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  padding: 0.32rem 0.7rem;
  border: 0;
  border-radius: 999px;
  background: rgba(222, 213, 201, 0.36);
  color: var(--ink);
  font-size: 0.88rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  transition: background-color 0.14s ease, color 0.14s ease, transform 0.14s ease;
}

.puzzle-tag-pill:hover,
.puzzle-tag-pill:focus {
  background: rgba(222, 213, 201, 0.58);
  color: var(--ink);
  text-decoration: none;
  transform: translateY(-1px);
}

/* Custom footer adjustments */
footer.heygg-body h3 {
  font-family: "Nunito Sans";
  font-style: normal;
  font-weight: 800;
  font-size: 14px;
  line-height: 150%;
  text-transform: uppercase;
  text-align: left;
}
footer.heygg-body {
  margin-top: 80px;
}

/* Override ajaxlink color in footer */
footer.heygg-body .ajaxlink {
  color: inherit;
  cursor: pointer;
}

footer.heygg-body .ajaxlink:hover {
  color: #ff6741;
  text-decoration: none;
}

footer.heygg-body .ot-sdk-show-settings {
  color: inherit;
  cursor: pointer;
}

footer.heygg-body .ot-sdk-show-settings:hover {
  color: #ff6741;
  text-decoration: none;
}

/* Homepage category links section */
.category-links {
  margin-bottom: 20px;
}

/* Category cards share the same shape as puzzle gallery cards: image area
   on top, white footer with title + stat row. */
.category-card {
  display: block;
  text-decoration: none;
  color: var(--ink);
  margin-bottom: 12px;
}

.category-card:hover,
.category-card:focus {
  text-decoration: none;
  color: var(--ink);
}

.category-card .category-thumb {
  transition: transform 0.14s ease-out;
}
.category-card .category-meta {
  transition: transform 0.14s ease-out, box-shadow 0.14s ease-out;
}

@media (hover: hover) {
  .category-card:hover .category-thumb,
  .category-card:hover .category-meta {
    transform: translateY(-4px);
  }
  .category-card:hover .category-meta {
    box-shadow: 0 14px 14px -12px rgba(0, 0, 0, 0.22);
  }
}

.category-thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  background: #fff;
}

.category-thumb img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Hey Good Game cross-promo recommendations rendered into the
   #congrats modal's .congrats-bottom container when a puzzle finishes.
   Single-line layout matches the Queens Ultimate GameCompleteModal —
   icon · "reason ·" · link · chevron — instead of stacked cards. Each
   row reads like "High win rate on Daily · Crosswordle →". */
.heygg-recs {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin: 10px auto 4px;
  padding: 0;
}

.heygg-rec {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 0;
  font-size: 0.82rem;
  line-height: 1.3;
  color: var(--muted, #636e72);
  text-decoration: none;
  max-width: 100%;
}

.heygg-rec:hover {
  text-decoration: none;
  opacity: 0.75;
}

.heygg-rec-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  width: 20px;
  height: 20px;
}

.heygg-rec-icon img {
  display: block;
  width: 20px;
  height: 20px;
  border-radius: 4px;
}

.heygg-rec-icon-fallback {
  background: var(--mirthtile, #9bded8);
  border-radius: 4px;
}

.heygg-rec-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.heygg-rec-link {
  color: var(--ink, #191817);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
}

/* Tiny chevron-right built from CSS borders — matches the heygg pattern,
   keeps the bundle free of an SVG dependency just for one decorative
   character. */
.heygg-rec-arrow {
  flex-shrink: 0;
  display: inline-block;
  width: 5px;
  height: 5px;
  border-right: 1.5px solid var(--muted, #636e72);
  border-bottom: 1.5px solid var(--muted, #636e72);
  transform: rotate(-45deg);
  margin-left: 2px;
}

/* Streak-at-risk reads more urgent in the heygg system; tint the link
   accent to a warm orange so it pops without becoming a button. */
.heygg-rec-streak-at-risk .heygg-rec-link {
  color: #b8541f;
}

/* Reserved 300x250 ad slot in the puzzle-complete (#congrats) modal.
   Always renders the box so the modal layout doesn't shift when an ad
   creative loads in. Dashed border + "Advertisement" label make the
   reserved space visible during dev/empty states. When an ad fills the
   slot, the creative covers the label and the border is hidden by the
   ad's own backdrop. */
.congrats-ad-slot {
  position: relative;
  width: 300px;
  height: 250px;
  margin: 16px auto;
  border: 1px dashed var(--border, rgba(0, 0, 0, 0.22));
  background: rgba(0, 0, 0, 0.02);
}

/* "Advertisement" label sits behind the ad layer via absolute
   positioning, so when GAM/AdSense injects an iframe the creative
   covers it without flexbox layout fights. */
.congrats-ad-slot::before {
  content: 'Advertisement';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted, #94908a);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  pointer-events: none;
}

/* Once the ad iframe lands, drop the placeholder chrome so the creative
   reads as a real ad, not a framed box. */
.congrats-ad-slot:has(iframe) {
  border-color: transparent;
  background: transparent;
}

.congrats-ad-slot:has(iframe)::before {
  display: none;
}

/* Embossed 2x2 jigsaw-cut overlay for category covers built from four
   puzzle tiles. Skipped on DB-driven single-image thumbnails (no
   .category-thumb-grid modifier) since the cuts would etch a fake grid
   across an unrelated photo. */
.category-thumb-grid::after {
  content: '';
  position: absolute;
  inset: 0;
  background: url('/images/jigsaw-overlay-2x2.svg') center / 100% 100% no-repeat;
  mix-blend-mode: overlay;
  opacity: 0.85;
  pointer-events: none;
  z-index: 1;
}

.category-thumb.no-thumb {
  background-color: #e9ecef;
}

.category-thumb.all-thumb {
  background: linear-gradient(135deg, var(--mirthtile), var(--mirthtile-deep));
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.category-thumb.all-thumb .all-icon {
  width: 56px;
  height: 56px;
  color: #fff;
  flex: none;
  /* Both the stroke layer (currentColor) and the duotone fill rect deepen
     together because all layers reference currentColor. */
  transition: color 0.18s ease;
}
.all-categories:hover .all-icon,
.all-categories:focus .all-icon {
  color: var(--ink);
}

/* Footer mirrors .gallery-meta exactly so the card shape is identical
   to puzzle/share cards on the same page. */
.category-meta {
  padding: 9px 10px 11px;
  background: var(--surface);
  border-bottom-left-radius: 10px;
  border-bottom-right-radius: 10px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.category-name {
  display: block;
  font-weight: 700;
  font-size: 0.92rem;
  line-height: 1.3;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
  min-width: 0;
}

.category-count {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--muted);
  flex: 0 0 auto;
  white-space: nowrap;
}

.category-count svg {
  width: 16px;
  height: 16px;
  flex: none;
  opacity: 0.7;
}

/* Migration banner styles */
.migration-banner {
  background: #dff3e8;             /* ~22% mix of var(--snapmint) into white */
  color: var(--ink);
  padding: 16px 24px;
  margin-top: 16px;
  margin-bottom: 24px;
  border-radius: 8px;
  border-left: 4px solid var(--snapmint);
}

.migration-banner-text {
  font-size: 16px;
  line-height: 1.5;
  text-align: center;
  margin: 0;
}

.migration-banner-text strong {
  font-weight: 700;
}

.migration-banner-text .banner-emoji {
  margin-right: 6px;
}

.migration-banner.hidden {
  display: none;
}

/* Responsive adjustments */
@media (max-width: 768px) {
  .migration-banner {
    padding: 12px 16px;
  }

  .migration-banner-text {
    font-size: 14px;
  }
}

/* ===== Make-Puzzle hero (Mini Sudoku-style) ===== */
.make-puzzle-hero {
  background: var(--mirthtile);
  padding: 56px 0 72px;
  /* full-bleed: escape the .container-fluid wrapper from layout.pug */
  margin: -8px calc(50% - 50vw) 0;
}

.make-puzzle-hero-text {
  padding-right: 64px;
  margin-bottom: 32px;
}

@media (max-width: 991.98px) {
  /* On stacked/mobile layouts the right-padding becomes wasted space */
  .make-puzzle-hero-text { padding-right: 0; }
}

@media (min-width: 992px) {
  .make-puzzle-hero-text { margin-bottom: 0; }
}

.make-puzzle-hero .make-puzzle-title {
  font-size: 2.4rem;
  font-weight: 800;
  line-height: 1.04;
  letter-spacing: -0.022em;
  margin: 0 0 16px;
  /* Pin to fixed dark — the hero bg is a fixed mint that doesn't flip
     with the theme, so the text shouldn't either. */
  color: #1a1410;
  text-wrap: balance;
}

@media (min-width: 768px) {
  .make-puzzle-hero .make-puzzle-title { font-size: 3rem; }
}

.make-puzzle-title-sub {
  display: block;
  margin-top: 10px;
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.3;
  opacity: 0.62;
}

.make-puzzle-hero-tag {
  font-size: 1.0625rem;
  line-height: 1.55;
  color: #1a1410;
  opacity: 0.85;
  margin: 0;
  max-width: 460px;
  text-wrap: pretty;
}

.make-puzzle-tool-card {
  background: var(--surface);
  /* Outer radius is larger than the inner dropzone radius (12px) so the
     curves feel proportionally scaled — concentric arcs read as
     intentional, equal radii read as a mistake. */
  border-radius: 22px;
  padding: 24px;
  box-shadow: 0 8px 0 0 rgba(53, 122, 130, 0.24);
}

/* Cross-link CTA above the Related Puzzles area on /puzzle/:slug and
   /share/:slug pages. Slim editorial line — matches .make-puzzle-outro
   in tone, sends high-intent post-play traffic to /make-puzzle. */
.make-own-cta-inline {
  margin: 24px auto 8px;
  text-align: center;
  max-width: 720px;
  padding: 0 1rem;
}

.make-own-cta-icon {
  display: block;
  width: 96px;
  height: 52px;
  margin: 0 auto 10px;
  color: var(--mirthtile-deep);
  opacity: 0.85;
}

.make-own-cta-line {
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.55;
  color: var(--muted);
  /* Avoid one-word orphan lines (e.g. "signup." stranded on its own line)
     by letting the browser balance line lengths. */
  text-wrap: balance;
}

.make-own-cta-line a {
  font-weight: 700;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 2px;
}

.make-own-cta-line a:hover {
  text-decoration-color: currentColor;
  opacity: 0.85;
}

@media (min-width: 768px) {
  .make-puzzle-tool-card { padding: 32px; }
}

/* Inside the hero tool card, kill Bootstrap's column constraints from
   inc/create.pug so the dropzone fills the card width. */
.make-puzzle-tool-card .row.justify-content-center {
  margin-left: 0;
  margin-right: 0;
}
.make-puzzle-tool-card .row.justify-content-center > [class*="col-"] {
  max-width: 100%;
  flex: 0 0 100%;
  padding-left: 0;
  padding-right: 0;
}

/* ===== Make-Puzzle feature list (single column, icon + content) ===== */
.make-puzzle-features {
  padding: 56px 0 16px;
}

.make-puzzle-feature {
  display: flex;
  gap: 18px;
  align-items: flex-start;
  margin-bottom: 32px;
}

.make-puzzle-feature-icon {
  flex: none;
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: rgba(255, 183, 3, 0.18);
  color: #c98800;
  display: flex;
  align-items: center;
  justify-content: center;
}

.make-puzzle-feature-icon svg {
  width: 24px;
  height: 24px;
}

.make-puzzle-feature-content {
  flex: 1 1 auto;
  min-width: 0;       /* allow text to wrap inside the flex parent */
  padding-top: 4px;
}

.make-puzzle-feature h3 {
  font-size: 1.05rem;
  font-weight: 800;
  margin: 0 0 4px;
  color: var(--ink);
}

.make-puzzle-feature p {
  font-size: 0.95rem;
  color: var(--muted);
  line-height: 1.55;
  margin: 0;
  max-width: 62ch;
  text-wrap: pretty;
}

/* ===== Make-Puzzle upload preview (post-upload, replaces dropzone) ===== */
.upload-preview {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  background: #ffffff;
  line-height: 0; /* kill the inline-image gap so the bg matches img bounds */
}

/* When a preview is active, zero the card's padding so the preview fills
   edge-to-edge — and re-pad the controls/TOS below explicitly so they
   keep their breathing room. This avoids fighting Bootstrap col/row
   constraints with negative-margin tricks. */
.make-puzzle-tool-card:has(#createContainer.has-preview) {
  padding: 0;
}
.make-puzzle-tool-card:has(#createContainer.has-preview) #createContainer {
  margin-top: 0;
}

#createContainer.has-preview .upload-preview {
  margin-bottom: 16px;
  border-radius: 22px 22px 0 0;
}

#createContainer.has-preview .upload-tos,
#createContainer.has-preview #thumbnailContainer {
  padding-left: 24px;
  padding-right: 24px;
}

#createContainer.has-preview #thumbnailContainer {
  padding-bottom: 24px;
}

@media (min-width: 768px) {
  #createContainer.has-preview .upload-tos,
  #createContainer.has-preview #thumbnailContainer {
    padding-left: 32px;
    padding-right: 32px;
  }
  #createContainer.has-preview #thumbnailContainer {
    padding-bottom: 32px;
  }
}

.upload-preview img {
  display: block;
  width: 100%;
  height: auto;
  cursor: pointer;
}

/* Canvas is sized & positioned inline from renderModePreview() — see the
   comment there for the geometry. .upload-preview's overflow:hidden clips
   the overhang to the container's rounded rectangle. */
.upload-puzzle-preview-canvas {
  position: absolute;
  display: none;
  pointer-events: none;
  transition: opacity 220ms ease;
}

.upload-preview.is-loading .upload-puzzle-preview-canvas {
  opacity: 0;
}

.upload-preview-spinner {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0;
  transition: opacity 220ms ease;
  z-index: 2;
}

.upload-preview.is-loading .upload-preview-spinner {
  opacity: 1;
}

.upload-preview-spinner-track {
  stroke: rgba(184, 222, 218, 0.35);
}

.upload-preview-spinner-arc {
  stroke: var(--mirthtile, #6fbfb7);
  stroke-dasharray: 90 200;
  transform-origin: center;
  animation: upload-preview-spin 0.9s linear infinite;
}

@keyframes upload-preview-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* When the engine preview is active, hide the raw img — canvas shows the photo */
.upload-preview.has-pieces #uploadPreviewImage {
  opacity: 0;
}

.upload-preview.has-pieces .upload-puzzle-preview-canvas {
  display: block;
}

.upload-reset {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 15px 8px 12px;
  border: none;
  border-radius: 12px;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(255, 255, 255, 0.94));
  color: var(--ink);
  font-weight: 700;
  font-size: 0.82rem;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(54, 43, 31, 0.16);
  transition: background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.upload-reset:hover {
  background:
    linear-gradient(180deg, #ffffff, #fff6df);
  box-shadow: 0 5px 14px rgba(54, 43, 31, 0.22);
  transform: translateY(-1px);
}

.upload-reset:active {
  box-shadow: 0 2px 7px rgba(54, 43, 31, 0.18);
  transform: translateY(0);
}

.upload-reset svg {
  display: block;
  flex: none;
}

@media (prefers-reduced-motion: reduce) {
  .upload-reset {
    transition: background-color 0.15s ease, box-shadow 0.15s ease;
  }

  .upload-reset:hover,
  .upload-reset:active {
    transform: none;
  }
}

/* When the preview is visible, hide the bottom split-row that shows
   the small thumbnail canvas + the CTA buttons in a 2-column layout.
   The CTAs get full-width treatment below, as a dedicated stack. */
#createContainer.has-preview #thumbnailContainer .row.mt-3:last-of-type .col-md-6.text-center {
  display: none;
}
#createContainer.has-preview #thumbnailContainer .row.mt-3:last-of-type .col-md-6:not(.text-center) {
  flex: 0 0 100%;
  max-width: 100%;
}
#createContainer.has-preview #thumbnailContainer {
  margin-top: 24px;
}
#createContainer.has-preview #thumbnailContainer > .row.mt-3 {
  margin-top: 22px !important;
}
#createContainer.has-preview #thumbnailContainer > .row.mt-3:first-child {
  margin-top: 0 !important;
}

/* ===== Make-Puzzle thumbnail container (post-upload form) ===== */
#thumbnailContainer #makeDifficultyRow > p,
#thumbnailContainer #makeModeRow > p {
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 10px;
}
#thumbnailContainer #makeDifficultyRow > p > strong,
#thumbnailContainer #makeModeRow > p > strong {
  font-weight: inherit;
}

/* Option-chip rail: label sits above (width:100% forces a row break), then
   chips wrap horizontally with consistent gap. */
#thumbnailContainer #makeDifficultyRow,
#thumbnailContainer #makeModeRow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 9px;
}
#thumbnailContainer #makeDifficultyRow .form-check.form-check-inline,
#thumbnailContainer #makeModeRow .form-check.form-check-inline {
  display: inline-flex;
  position: relative;
  margin: 0;
  padding: 0;
}

/* Hide the native radio circle */
#thumbnailContainer input[name="makeDifficulty"],
#thumbnailContainer input[name="makeMode"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 1px;
  height: 1px;
}

/* Style the label as a compact rounded-rectangle chip */
#thumbnailContainer input[name="makeDifficulty"] + label.form-check-label,
#thumbnailContainer input[name="makeMode"] + label.form-check-label {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 7px 13px;
  border: 1px solid var(--hairline);
  border-radius: 9px;
  background: var(--surface);
  color: var(--ink);
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
#thumbnailContainer input[name="makeDifficulty"] + label.form-check-label:hover,
#thumbnailContainer input[name="makeMode"] + label.form-check-label:hover {
  border-color: var(--mirthtile);
  background: #f1faf8;
  color: #191817;
  transform: translateY(-1px);
}
:root[data-theme="dark"] #thumbnailContainer input[name="makeDifficulty"] + label.form-check-label:hover,
:root[data-theme="dark"] #thumbnailContainer input[name="makeMode"] + label.form-check-label:hover {
  background: rgba(155, 222, 216, 0.10);
  color: var(--ink);
  border-color: rgba(155, 222, 216, 0.45);
}

/* Selected state — mint fill stays light in both themes, so the
   label needs a fixed dark color or it disappears in dark mode. */
#thumbnailContainer input[name="makeDifficulty"]:checked + label.form-check-label,
#thumbnailContainer input[name="makeMode"]:checked + label.form-check-label {
  background: var(--mirthtile);
  border-color: var(--mirthtile);
  color: #191817;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.32);
}
#thumbnailContainer input[name="makeDifficulty"]:focus-visible + label.form-check-label,
#thumbnailContainer input[name="makeMode"]:focus-visible + label.form-check-label {
  box-shadow: 0 0 0 3px rgba(155, 222, 216, 0.42);
}

/* Force the section label (<p>Difficulty</p>) onto its own row so the
   chips wrap on the lines below it, not next to it. */
#thumbnailContainer #makeDifficultyRow > p,
#thumbnailContainer #makeModeRow > p {
  flex-basis: 100%;
  width: 100%;
}

/* ===== Challenge picker divider + disclosure block ===== */

/* Visual separator between cut-style pills and challenge-mode pills.
   Reads as "or play a different game" so users understand challenges
   are alternatives to cut styles, not additive. */
.challenge-divider {
  flex-basis: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 18px 0 12px;
  color: var(--muted, #636e72);
}

.challenge-divider::before,
.challenge-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, transparent, rgba(99, 110, 114, 0.25), transparent);
}

.challenge-divider-text {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Container for the disclosure block that appears under the mode pills
   when Math or Quiz is selected. Empty (no children) when a cut style
   is picked — collapses to zero height. */
.challengeDetails:empty {
  display: none;
}

.challenge-block {
  margin-top: 14px;
  padding: 14px 16px;
  background: rgba(184, 222, 218, 0.14);
  border: 1px solid rgba(184, 222, 218, 0.5);
  border-radius: 14px;
}

.challenge-explainer {
  margin: 0 0 10px;
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--ink, #191817);
}

/* Summary row — the collapsed-state default that shows what'll happen
   when the user hits Play, plus a Customize toggle. */
.challenge-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 10px 14px;
  background: var(--surface, #fffdf8);
  border: 1px solid rgba(99, 110, 114, 0.2);
  border-radius: 10px;
  font-size: 0.95rem;
  color: var(--ink, #191817);
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.challenge-summary:hover {
  border-color: var(--mirthtile, #6fbfb7);
}

.challenge-summary-label {
  color: var(--muted, #636e72);
}

.challenge-summary-value {
  color: var(--ink, #191817);
  font-weight: 600;
}

.challenge-summary-toggle {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--mirthtile-deep, #357a82);
  white-space: nowrap;
}

.challenge-summary[aria-expanded="true"] {
  border-color: var(--mirthtile, #6fbfb7);
  box-shadow: 0 0 0 3px rgba(155, 222, 216, 0.24);
}

/* Expanded options panel — list of choices, with a single accent border
   on whichever is checked. */
.challenge-options {
  margin-top: 12px;
  display: grid;
  gap: 8px;
}

.challenge-options[hidden] {
  display: none;
}

.challenge-option {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0;
  padding: 10px 12px;
  background: var(--surface, #fffdf8);
  border: 1px solid rgba(99, 110, 114, 0.18);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 0.15s, background-color 0.15s;
}

.challenge-option:hover {
  border-color: var(--mirthtile, #6fbfb7);
}

.challenge-option input[type="radio"] {
  margin: 4px 0 0;
  accent-color: var(--mirthtile-deep, #357a82);
  flex-shrink: 0;
}

.challenge-option:has(input:checked) {
  border-color: var(--mirthtile, #6fbfb7);
  background: rgba(184, 222, 218, 0.18);
}

.challenge-option-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.challenge-option-title {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink, #191817);
}

.challenge-option-meta {
  font-size: 0.82rem;
  color: var(--muted, #636e72);
}

.challenge-select {
  width: 100%;
}

.challenge-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

/* Action buttons inside the challenge panel (New quiz / Manage). Use the
   same pill geometry as the cut-style / difficulty pills above so the
   block reads as one design system, not Bootstrap leaking through. */
.challenge-actions .btn {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 7px 13px;
  margin: 0;
  background: var(--surface, #fffdf8);
  border: 1px solid var(--hairline, rgba(99, 110, 114, 0.2));
  border-radius: 9px;
  color: var(--ink, #191817);
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.12s ease;
}

.challenge-actions .btn:hover {
  border-color: var(--mirthtile, #6fbfb7);
  background: #f1faf8;
  color: var(--ink, #191817);
  transform: translateY(-1px);
}

.challenge-actions .btn:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(155, 222, 216, 0.32);
}

/* ===== Quiz creation/edit form (modal) ===== */
/* Scoped to .quiz-form so this only restyles the quiz builder modal, not
   any generic .form-control elsewhere on the site. */

/* Modal shell — match the make-puzzle tool card so the modal reads as part
   of the same surface family (22px radius, teal drop shadow). */
#quizModal .modal-content,
#manageModal .modal-content {
  background: var(--surface, #fffdf8);
  border: none;
  border-radius: 22px;
  box-shadow: 0 12px 0 0 rgba(53, 122, 130, 0.18),
              0 24px 60px -20px rgba(20, 40, 50, 0.25);
  overflow: hidden;
}

#quizModal .modal-header,
#manageModal .modal-header {
  padding: 22px 28px 18px;
  border-bottom: 1px solid var(--hairline, rgba(99, 110, 114, 0.15));
}

#quizModal .modal-title,
#manageModal .modal-title {
  font-weight: 800;
  font-size: 1.35rem;
  color: var(--ink, #191817);
  letter-spacing: -0.01em;
}

#quizModal .modal-header .close,
#manageModal .modal-header .close {
  width: 32px;
  height: 32px;
  margin: -6px -6px -6px 0;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--muted, #636e72);
  font-size: 1.4rem;
  line-height: 1;
  opacity: 1;
  transition: background-color 0.15s ease, color 0.15s ease;
}

#quizModal .modal-header .close:hover,
#manageModal .modal-header .close:hover {
  background: rgba(99, 110, 114, 0.1);
  color: var(--ink, #191817);
}

#quizModal .modal-body,
#manageModal .modal-body {
  padding: 24px 28px 28px;
}

/* Modal backdrop — slightly warmer to match the page's mirthtile palette
   rather than Bootstrap's pure black. */
.modal-backdrop.show {
  background-color: rgba(20, 40, 50, 0.55);
  opacity: 1;
}

/* ===== Standalone /quiz/edit/:id page ===== */
/* The edit page reuses the same form markup as the new-quiz modal but
   needs page chrome since it's not inside a Bootstrap modal. */

.quiz-edit-page {
  padding: 24px 0 64px;
}

.quiz-edit-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
  max-width: 880px;
  margin-left: auto;
  margin-right: auto;
}

.quiz-edit-back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px 6px 6px;
  border-radius: 8px;
  color: var(--muted, #636e72);
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 600;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.quiz-edit-back:hover {
  background: rgba(99, 110, 114, 0.08);
  color: var(--ink, #191817);
  text-decoration: none;
}

.quiz-edit-title {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--ink, #191817);
  letter-spacing: -0.01em;
}

/* Tool-card surface for the form, matching make-puzzle's visual language. */
.quiz-edit-card {
  max-width: 880px;
  margin: 0 auto;
  background: var(--surface, #fffdf8);
  border-radius: 22px;
  padding: 28px 32px 32px;
  box-shadow: 0 8px 0 0 rgba(53, 122, 130, 0.24);
}

@media (max-width: 767px) {
  .quiz-edit-card {
    padding: 20px 18px 24px;
    border-radius: 18px;
  }
  .quiz-edit-page {
    padding: 16px 0 48px;
  }
}

/* The Save row in quiz.pug uses Bootstrap's .col .text-right .col grid
   which leaves the button floating awkwardly on a wide page. Override to
   center it as a single confident CTA. */
.quiz-edit-card .quiz-form > .row:last-child {
  margin-top: 8px;
  justify-content: center;
}

.quiz-edit-card .quiz-form > .row:last-child .col.text-right {
  flex: 0 0 auto;
  max-width: 320px;
  text-align: center !important;
}

.quiz-edit-card .quiz-form > .row:last-child .col:not(.text-right) {
  display: none;
}

/* ===== Manage Quizzes list (inline, replaces iframe) ===== */

.quiz-manage-loading,
.quiz-manage-empty {
  padding: 24px 4px;
  color: var(--muted, #636e72);
  text-align: center;
}

.quiz-manage-empty p {
  margin: 0;
  font-size: 0.95rem;
}

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

.quiz-manage-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  background: var(--surface, #fffdf8);
  border: 1px solid var(--hairline, rgba(99, 110, 114, 0.18));
  border-radius: 10px;
  transition: border-color 0.15s ease;
}

.quiz-manage-item:hover {
  border-color: var(--mirthtile, #6fbfb7);
}

.quiz-manage-name {
  font-weight: 600;
  color: var(--ink, #191817);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.quiz-manage-actions {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.quiz-manage-edit {
  display: inline-flex;
  align-items: center;
  padding: 6px 12px;
  border-radius: 8px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--mirthtile-deep, #357a82);
  text-decoration: none;
  transition: background-color 0.15s ease;
}

.quiz-manage-edit:hover {
  background: rgba(155, 222, 216, 0.18);
  color: var(--mirthtile-deep, #357a82);
  text-decoration: none;
}

.quiz-manage-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 8px;
  color: var(--muted, #636e72);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.quiz-manage-delete:hover {
  background: rgba(255, 103, 65, 0.12);
  color: #c44523;
}

.quiz-form .quiz-meta {
  margin-top: 12px;
}

/* Field labels — uppercase, muted, matches DIFFICULTY/MODE rhythm. */
.quiz-form label {
  display: block;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted, #636e72);
  margin: 0 0 6px;
}

/* The "Question N" label uses a strong wrapper; let it sit on its own and
   keep the upper-case/letter-spacing treatment via the parent rule. */
.quiz-form label strong {
  font-weight: 800;
}

/* Inputs — pill-friendly radius, brand focus state. */
.quiz-form .form-control {
  height: 40px;
  padding: 8px 12px;
  background: var(--surface, #fffdf8);
  border: 1px solid var(--hairline, rgba(99, 110, 114, 0.25));
  border-radius: 10px;
  color: var(--ink, #191817);
  font-size: 0.95rem;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.quiz-form .form-control:hover {
  border-color: var(--mirthtile, #6fbfb7);
}

.quiz-form .form-control:focus {
  outline: none;
  border-color: var(--mirthtile, #6fbfb7);
  box-shadow: 0 0 0 3px rgba(155, 222, 216, 0.28);
}

/* Question separator — subtler than Bootstrap's default <hr>. */
.quiz-form hr {
  border: 0;
  border-top: 1px solid var(--hairline, rgba(99, 110, 114, 0.18));
  margin: 20px 0 16px;
}

/* Delete-question icon button — replaces the bare "𝑥" glyph with a
   roundel that matches the page's button language. */
.quiz-form .delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  margin-top: 22px;
  border-radius: 8px;
  background: transparent;
  color: var(--muted, #636e72);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.quiz-form .delete:hover {
  background: rgba(255, 103, 65, 0.12);
  color: #c44523;
}

/* + New Question — pill style matching cut-style / difficulty buttons. */
.quiz-form .add-question {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 8px 14px;
  margin-top: 12px;
  background: var(--surface, #fffdf8);
  border: 1px solid var(--hairline, rgba(99, 110, 114, 0.2));
  border-radius: 9px;
  color: var(--ink, #191817);
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1;
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.12s ease;
}

.quiz-form .add-question:hover {
  border-color: var(--mirthtile, #6fbfb7);
  background: #f1faf8;
  color: var(--ink, #191817);
  transform: translateY(-1px);
}

/* Spacing for the incorrect-answer row so the 4 inputs aren't crammed. */
.quiz-form .row.mt-2 .col {
  margin-bottom: 8px;
}

/* Thumbnail preview tile */
#thumbnailContainer #thumbnailCanvas {
  width: 100% !important;
  max-width: 240px;
  height: auto;
  border-radius: 10px;
  background: var(--bg);
  display: block;
}

/* Post-upload CTA stack */
#thumbnailContainer #nextContainer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
/* Layout for secondary CTAs in the post-upload stack. Excludes #playNext
   which is the primary action and gets its full visual treatment from the
   shared .btn-mint-primary class. */
#thumbnailContainer #nextContainer .btn:not(#playNext) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin: 0;
  min-height: 44px;
  padding: 10px 16px;
  font-weight: 700;
  font-size: 0.88rem;
  border-radius: 10px;
  border: 1px solid transparent;
  line-height: 1.1;
  transition: background-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.12s ease;
}

#thumbnailContainer #nextContainer .btn:not(#playNext) svg {
  flex-shrink: 0;
  color: var(--mirthtile-deep, #357a82);
}
/* Layout-only: span the full grid row inside #nextContainer. Visual
   treatment comes from the shared .btn.btn-mint-primary class. */
#thumbnailContainer #playNext {
  grid-column: 1 / -1;
}
#thumbnailContainer #shareUpload,
#thumbnailContainer #publicUpload {
  background: rgba(255, 255, 255, 0.64);
  color: var(--ink);
  border-color: var(--hairline);
}
#thumbnailContainer #shareUpload:hover,
#thumbnailContainer #publicUpload:hover {
  border-color: var(--mirthtile);
  background: #f1faf8;
  color: #191817;
  transform: translateY(-1px);
}
/* Dark mode — the translucent white fill becomes a washed-out grey
   pill against the dark page. Swap to a lifted dark surface that
   reads as a clear secondary action. */
:root[data-theme="dark"] #thumbnailContainer #shareUpload,
:root[data-theme="dark"] #thumbnailContainer #publicUpload {
  background: rgba(255, 255, 255, 0.04);
  color: var(--ink);
  border-color: var(--hairline);
}
:root[data-theme="dark"] #thumbnailContainer #shareUpload:hover,
:root[data-theme="dark"] #thumbnailContainer #publicUpload:hover {
  background: rgba(155, 222, 216, 0.10);
  color: var(--ink);
  border-color: rgba(155, 222, 216, 0.45);
}

@media (max-width: 575.98px) {
  #thumbnailContainer #nextContainer {
    grid-template-columns: 1fr;
  }

  #thumbnailContainer #nextContainer .btn {
    grid-column: 1 / -1;
  }
}

@media (prefers-reduced-motion: reduce) {
  #thumbnailContainer input[name="makeDifficulty"] + label.form-check-label,
  #thumbnailContainer input[name="makeMode"] + label.form-check-label,
  #thumbnailContainer #nextContainer .btn {
    transition: background-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  }

  #thumbnailContainer input[name="makeDifficulty"] + label.form-check-label:hover,
  #thumbnailContainer input[name="makeMode"] + label.form-check-label:hover,
  #thumbnailContainer #nextContainer .btn:hover,
  #thumbnailContainer #nextContainer .btn:active {
    transform: none;
  }
}

/* ===== Make-Puzzle SEO landing copy ===== */
.make-puzzle-seo {
  margin: 48px 0 24px;
  color: var(--ink);
  font-size: 1.0625rem;
  line-height: 1.7;
}

.make-puzzle-seo h2 {
  font-size: 1.6rem;
  font-weight: 800;
  margin: 36px 0 12px;
  color: var(--ink);
}

.make-puzzle-seo h2:first-child {
  margin-top: 0;
}

.make-puzzle-seo h3 {
  font-size: 1.1rem;
  font-weight: 700;
  margin: 20px 0 6px;
  color: var(--ink);
}

/* Sub-section tip heads inside the "What makes a great photo" section.
   Pulled tighter so they read as bullet labels under the parent H2 rather
   than independent sections. */
.make-puzzle-tip-head {
  font-size: 1rem !important;
  margin: 22px 0 4px !important;
  color: var(--ink, #191817) !important;
  letter-spacing: -0.005em;
}

.make-puzzle-seo p {
  margin: 0 0 14px;
}

.make-puzzle-seo a {
  color: var(--nooksky-deep);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Scoped hover override needed: the base rule above (0-1-1) outweighs
   the global a:hover (0-1-0), so we have to restate the hover here. */
.make-puzzle-seo a:hover,
.make-puzzle-seo a:focus {
  color: var(--link-hover);
  text-decoration: none;
}

.make-puzzle-steps {
  padding-left: 1.25em;
  margin: 0 0 14px;
}

.make-puzzle-steps li {
  margin-bottom: 10px;
}

.make-puzzle-steps li strong {
  display: inline;
  margin-right: 4px;
}

.make-puzzle-faq h3 {
  margin-top: 18px;
}

.make-puzzle-faq h3:first-child {
  margin-top: 8px;
}

/* Homepage FAQ — adds topical depth + FAQPage schema for AI Overview /
   featured-snippet capture. Visual style mirrors .make-puzzle-faq. */
.home-faq {
  margin: 48px 0 32px;
  color: var(--ink);
  font-size: 1.0625rem;
  line-height: 1.7;
}

.home-faq-icon {
  display: block;
  width: 96px;
  height: 96px;
  margin: 0 0 12px;
}

.home-faq .section-heading {
  font-size: 1.6rem;
  font-weight: 800;
  margin: 0 0 18px;
}

.home-faq-list h3 {
  font-size: 1.1rem;
  font-weight: 700;
  margin: 22px 0 6px;
  color: var(--ink);
}

.home-faq-list h3:first-child {
  margin-top: 8px;
}

.home-faq-list p {
  margin: 0 0 14px;
}

.home-faq-list a {
  color: var(--nooksky-deep);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.home-faq-list a:hover,
.home-faq-list a:focus {
  color: var(--link-hover);
  text-decoration: none;
}

.make-puzzle-outro {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid var(--hairline);
  color: var(--muted);
}

/* --- Longitude ad slots (prototype placeholders) --- */
.ad-slot {
  display: flex;
  justify-content: center;
  width: 100%;
  margin: 16px 0;
}

.ad-slot__box {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  background: #f4f4f4;
  border: 1px dashed #c4c4c4;
  border-radius: 4px;
  color: #9a9a9a;
  font-family: "Nunito Sans", sans-serif;
  text-align: center;
}

.ad-slot__label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.ad-slot__meta {
  font-size: 10px;
  color: #b9b9b9;
  margin-top: 2px;
}

.ad-slot--leaderboard .ad-slot__box {
  width: 728px;
  max-width: 100%;
  height: 90px;
}

.ad-slot--in-feed .ad-slot__box {
  width: 728px;
  max-width: 100%;
  height: 250px;
}

.ad-slot--rectangle .ad-slot__box {
  width: 300px;
  max-width: 100%;
  height: 250px;
}

@media (max-width: 767px) {
  .ad-slot--leaderboard .ad-slot__box {
    width: 320px;
    height: 100px;
  }

  .ad-slot--in-feed .ad-slot__box {
    width: 300px;
    height: 250px;
  }
}

/* Mobile banner -- 320x50 standard IAB mobile unit, phone widths only.
   Sits at the top of the puzzle content, between the global header and
   the puzzle breadcrumbs. Hidden at >=768px so it never competes with the
   leaderboard slot or the right rail. */
.ad-slot--mobile-banner {
  display: none;
}

@media (max-width: 767.98px) {
  .ad-slot--mobile-banner {
    display: flex;
    justify-content: center;
    width: 100%;
    /* Match the global header's surface (#fffdf8) so the banner reads as
       part of the chrome band, not a stripe sitting on the page bg.
       Zero top padding/margin so the ad sits flush against the nav's
       bottom hairline -- the user wants no visible gap. */
    margin: 0;
    padding: 0 8px 8px;
    background: var(--surface, #fffdf8);
  }

  .ad-slot--mobile-banner .ad-slot__box {
    width: 320px;
    max-width: 100%;
    height: 50px;
  }

  /* Homepage / non-puzzle pages use a slightly warmer fill so the banner
     blends with the page bg under the nav. The puzzle player keeps the
     neutral --surface so it matches the puzzle nav band. */
  .ad-slot--mobile-banner[data-ad-placement="mobileAnchor"] {
    background: #fbf4ec;
  }

  /* On /make-puzzle the hero is the mint mirthtile color; match the
     banner bg so it reads as one continuous band into the hero. */
  body[data-page="make-puzzle"] .ad-slot--mobile-banner[data-ad-placement="mobileAnchor"] {
    background: var(--mirthtile, #9bded8);
  }

  /* When a content page leads with the mobile banner, neutralize the content
     wrapper's Bootstrap mt-2 (0.5rem) so the banner sits flush under the nav's
     bottom hairline -- no gap between the account bar and the ad. */
  .container-fluid.flexOne:has(> .ad-slot--mobile-banner:first-child) {
    /* Bootstrap's .mt-2 sets margin-top with !important, so we must too. */
    margin-top: 0 !important;
  }

  /* Content-page banner sits on the page background -- no fill band behind it.
     Full-bleed to the viewport edges (matching the make-puzzle hero's
     margin:0 -15px breakout) so its background spans edge to edge with no
     side gutters showing the page bg. */
  .ad-slot--mobile-banner[data-ad-placement="contentMobileBanner"] {
    background: transparent;
    width: calc(100% + 30px);
    margin-left: -15px;
    margin-right: -15px;
  }

  /* On /make-puzzle the hero is the mint mirthtile color; match it so the
     banner reads as one continuous band into the hero instead of a stripe on
     the page bg. */
  body[data-page="make-puzzle"] .ad-slot--mobile-banner[data-ad-placement="contentMobileBanner"] {
    background: var(--mirthtile, #9bded8);
  }

  /* The make-puzzle hero's 56px top padding is sized for sitting directly
     under the nav. When a filled banner sits above it, the ad already provides
     that separation, so trim the hero's top padding to avoid a big dead gap
     between the ad and the heading. Only when the ad actually fills (iframe);
     the empty/collapsed state keeps the original spacing. */
  .ad-slot--mobile-banner[data-ad-placement="contentMobileBanner"]:has(iframe) ~ .make-puzzle-hero {
    padding-top: 24px;
  }
}

/* Desktop anchor -- fixed to the bottom of the viewport, desktop only.
   Mirrors the anchor on queensultimate.com. In production the Longitude
   script injects its own #desktop-anchor; this placeholder simulates the
   footprint so the layout can be tuned before the real unit is wired in. */
.ad-slot--anchor {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 999;
  margin: 0;
  padding: 0;
  background: transparent;
}

.ad-slot--anchor .ad-slot__box {
  width: 728px;
  max-width: 100%;
  height: 90px;
}

/* Reserve space so the fixed anchor never covers page content. */
body.has-ad-anchor {
  padding-bottom: 106px;
}

@media (max-width: 800px) {
  .ad-slot--anchor {
    display: none;
  }

  body.has-ad-anchor {
    padding-bottom: 0;
  }
}

/* Production: the Longitude script injects its own #desktop-anchor.
   Keep it transparent and above page content (matches queensultimate.com). */
#desktop-anchor.active {
  background: none !important;
  z-index: 999 !important;
}

/* Drop the fixed desktop anchor beneath the congrats backdrop while the
   end-game modal is open. Backdrop is z-index 150; we drop the anchor to
   1 so the mint backdrop fully covers it instead of letting it bleed
   through. Covers both our placeholder slot and the production
   Longitude-injected #desktop-anchor. */
body.congrats-open .ad-slot--anchor,
body.congrats-open #desktop-anchor {
  z-index: 1 !important;
}

/* Puzzle play screen: when the desktop anchor is active, shrink the canvas
   so the play area sits ABOVE the anchor instead of behind it. The puzzle
   engine (CanvasUtility.setCanvasSize) sizes the drawing buffer from the
   canvas's CSS clientHeight, so constraining height here genuinely reserves
   the space -- the same technique the previous owner used for the mobile ad.
   Competitors (Jigsaw Explorer, JigsawPlanet) all reserve space this way. */
@media (min-width: 801px) {
  body.has-ad-anchor #myCanvas {
    height: calc(90vh - 160px);
    min-height: calc(90vh - 160px);
  }
}

/* Puzzle play screen: right-hand ad rail. Persistent at all desktop widths
   so the canvas knows its bounds at every breakpoint — modeled on
   online-solitaire.com. The rail inherits the felt texture via the
   --puzzle-texture custom prop (it lives inside #gameContainer) and
   layers a dark inset shadow on top, so it reads as part of the table
   but visually "off limits" — pieces won't land there because it looks
   like the edge of the play surface, not the play surface itself.
   Hidden below 992px so phones/small tablets keep full canvas width. */
.ad-slot--rail {
  display: none;
}

@media (min-width: 1024px) {
  .ad-slot--rail {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    /* 320px holds a 300x600 with 10px breathing room on each side.
       Kept at this width down to 1024px — we'd rather lose ~136px of
       canvas than fall back to a 160x600 skyscraper that nobody buys. */
    flex: 0 0 320px;
    width: 320px;
    margin: 0;
    padding: 12px 10px;
    align-self: stretch;

    /* Same felt texture as the canvas, but mixed against a darker
       variant of --puzzle-bg so the rail reads as "the same material,
       just shadowed". The first background-color line is a fallback for
       browsers that don't support color-mix (older Safari/Edge). */
    background-color: var(--puzzle-bg);
    background-color: color-mix(in srgb, var(--puzzle-bg) 88%, black 12%);
    background-image: var(--puzzle-texture);
    background-size: var(--puzzle-texture-size);
    background-repeat: repeat;
    background-blend-mode: var(--puzzle-texture-blend);

    border-left: 1px solid rgba(0, 0, 0, 0.12);
  }

  /* Sticky 300x600 half-page. Stays visible as the player scrolls the
     (potentially tall) canvas area. */
  .ad-slot--rail .ad-slot__box {
    position: sticky;
    top: 12px;
    width: 300px;
    height: 600px;
  }
}

/* Content pages (homepage, categories): right-hand 300x600 sidebar.
   Very large desktops only -- below the breakpoint the content keeps full
   width. Sits beside the content via the layout's .flexContainer flexbox. */
.ad-slot--content-rail {
  display: none;
}

@media (min-width: 1500px) {
  .ad-slot--content-rail {
    display: flex;
    flex: 0 0 312px;
    width: 312px;
    margin: 0;
    padding: 16px 6px 0;
    align-self: flex-start;
  }

  .ad-slot--content-rail .ad-slot__box {
    width: 300px;
    height: 600px;
  }
}

/* ---- Live lngtd unit divs (placeholders:false) ----
   lngtd fills a div whose id matches the unit name; .ad-unit reserves the
   footprint and centers it. Desktop/mobile are separate units sharing a
   position (e.g. below-canvas D_2/M_2) so we gate by breakpoint here. The
   .ad-slot--rail / --content-rail / --mobile-banner wrappers already gate
   their own device visibility (see rules above). */
.ad-unit {
  display: block;
  margin: 0 auto;
}

/* Mobile-only unit hidden on desktop; flips at the phone breakpoint. */
.ad-unit--mobile {
  display: none;
}

@media (max-width: 767.98px) {
  .ad-unit--desktop {
    display: none;
  }
  .ad-unit--mobile {
    display: block;
    margin: 0 auto;
  }
}

/* Below-canvas rectangle: 300x250 on every width (D_2 desktop / M_2 mobile). */
.ad-slot--rectangle .ad-unit {
  width: 300px;
  max-width: 100%;
  min-height: 250px;
}

/* Puzzle right rail: stacks two 300x250 units (puzzlesnap_D_1 + _D_2). The
   .ad-slot--rail wrapper is already a flex column with a 12px gap, so the two
   units sit one above the other. Top-aligned (not sticky) since two stacked
   sticky units at the same offset would overlap. lngtd has no tall unit. */
.ad-slot--rail {
  justify-content: flex-start;
}

.ad-slot--rail .ad-unit {
  flex: 0 0 auto;
  width: 300px;
  min-height: 250px;
}

/* Hosted outstream unit: stacks directly below the two 300x250s as the third
   rail item (same 300-wide footprint, 12px gap from the .ad-slot--rail flex
   column). Not docked/sticky -- it sits in the flow right under D_2. */
.ad-slot--rail #puzzlesnap_D_2_outstream {
  width: 300px;
  min-height: 250px;
}

/* Viewport-height guard: drop the third unit on short viewports where three
   stacked units + the anchor footprint won't fit, so it doesn't collide with
   the bottom anchor. The two display units carry the rail there. */
@media (max-height: 799.98px) {
  .ad-slot--rail #puzzlesnap_D_2_outstream {
    display: none;
  }
}

/* Content sidebar (home/category): single 300x250, sticky through scroll. */
.ad-slot--content-rail .ad-unit {
  position: sticky;
  top: 12px;
  width: 300px;
  min-height: 250px;
}

/* Mobile banner: 320x50 (puzzlesnap_M_1). */
.ad-slot--mobile-banner .ad-unit {
  width: 320px;
  max-width: 100%;
  min-height: 50px;
}

/* Win-modal unit (#modal_W_D_1) -- 300x250 centered in the congrats slot. */
#modal_W_D_1.ad-unit {
  width: 300px;
  max-width: 100%;
  min-height: 250px;
}
