/* ═══════════════════════════════════════════════════════════════════
   SAKURA 1000 — /art/play/puzzle.css
   Scoped under .sk-app. Builds on /css/keigen-core.css tokens
   (--color-*, --radius-*, --focus-ring). Desktop first.
   Table colours are read by puzzle.js from the --sk-* properties below,
   so the canvas follows the site's light/dark theme.
   ═══════════════════════════════════════════════════════════════════ */

.sk-app{
  --sk-bar-h:64px;
  /* Table palette: a calm, deep neutral that lets the violet read */
  --sk-surround:#1c1a23;
  --sk-table:#2a2733;
  --sk-board:#110f16;
  --sk-frame:rgba(255,255,255,.28);
  --sk-panel:rgba(20,18,27,.82);
  --sk-panel-text:#ebe8f3;
  --sk-panel-dim:#b3adc4;
  --sk-focus:#b9a4f5; /* focus ring on the dark stage (>= 3:1 against the table) */
  --sk-side:#15131b; /* the reference column beside the table (large screens) */
  padding-top:64px; /* the site nav's room (it scrolls with the page here: below) */
  background:var(--color-bg);
}
[data-theme="dark"] .sk-app{
  --sk-surround:#0d0c12;
  --sk-side:#08070c;
  --sk-table:#201e29;
  --sk-board:#08070b;
  --sk-frame:rgba(255,255,255,.2);
  --sk-panel:rgba(12,11,17,.86);
}

.sk-app [hidden]{display:none!important}

/* The site's nav is fixed to the top of the screen on other pages. Here
   it scrolls away with the page (it is the same nav, at the same place at
   the top of the page), because a fixed nav would lie over the table's
   top whenever the page is scrolled past it (owner, 2026-10-01: "nothing
   ever covers a piece"). With no fixed nav, nothing needs the site's
   scroll padding either (5rem, kept clear for the nav): the notify form,
   the table and the reference panel scroll to the top of the screen.
   Only /art/play loads this file. The phone menu, off screen to the
   right until opened, is held inside the nav's width (overflow-x: clip):
   with a nav that scrolls, it would otherwise widen the page, and a phone
   browser would zoom the page out to show it. */
body:has(.sk-app) .nav{position:absolute;overflow-x:clip}
html:has(.sk-app){scroll-padding-top:0}

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

/* ── Title + toolbar bar ── */
.sk-bar{
  display:flex;
  align-items:center;
  justify-content:space-between;
  flex-wrap:wrap;
  gap:.5rem 1.5rem;
  min-height:var(--sk-bar-h);
  padding:.5rem clamp(1rem,3vw,2rem);
  background:var(--color-surface);
  border-bottom:1px solid var(--color-border);
}
.sk-title{display:flex;flex-direction:column;gap:.1rem;min-width:0}
.sk-title .eyebrow{font-size:.7rem;letter-spacing:.14em;color:var(--color-accent-ui)}
.sk-title h1{
  font-family:'Fraunces','Noto Sans JP',Georgia,serif;
  font-weight:700;
  font-size:1.45rem;
  line-height:1.1;
  letter-spacing:-.02em;
  color:var(--color-text);
}

.sk-toolbar{display:flex;align-items:center;flex-wrap:wrap;gap:.5rem}
/* role="toolbar": the buttons only (one Tab stop, arrow keys inside) */
.sk-tools{display:flex;align-items:center;flex-wrap:wrap;gap:.5rem}
.sk-group{display:flex;align-items:center;gap:.35rem}
.sk-sep{width:1px;height:22px;background:var(--color-border-hover);margin:0 .2rem}
/* Hidden where the items either side of it wrap onto different rows
   (puzzle.js syncSeparators): it would dangle at a row's end */
.sk-sep.is-off{display:none}

.sk-chip{
  display:inline-flex;
  align-items:center;
  gap:.4rem;
  height:34px;
  padding:0 .8rem;
  border-radius:999px;
  background:var(--color-surface-alt);
  color:var(--color-text-secondary);
  font-size:.85rem;
  font-weight:500;
  white-space:nowrap;
}
.sk-chip strong{color:var(--color-text);font-weight:600}
.sk-chip code{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:.8rem;
  color:var(--color-text);
  letter-spacing:.03em;
}

.sk-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:.35rem;
  height:34px;
  min-width:34px;
  padding:0 .8rem;
  border-radius:var(--radius-sm,8px);
  border:1px solid var(--color-border-hover);
  background:var(--card-bg);
  color:var(--color-text);
  font-family:'Outfit','Noto Sans JP',system-ui,sans-serif;
  font-size:.875rem;
  font-weight:500;
  line-height:1;
  cursor:pointer;
  transition:border-color .2s var(--ease-breathe),background .2s var(--ease-breathe),color .2s var(--ease-breathe);
}
.sk-btn:hover{border-color:var(--color-primary-ui);background:var(--color-primary-soft)}
.sk-btn:focus-visible{outline:2px solid var(--color-primary-ui);outline-offset:2px;box-shadow:none}
.sk-btn[aria-pressed="true"]{border-color:var(--color-primary-ui);color:var(--color-primary-text);background:var(--color-primary-soft)}
/* Toggle buttons (aria-pressed: Edges only, Reference) carry a small check
   box, empty when off and ticked when on, so the state is a shape as well
   as a colour (brief: colour is never the only signal). The box takes the
   same room either way: pressing one never changes the bar's wrapping. */
.sk-btn[aria-pressed]{position:relative;padding-left:1.9rem}
.sk-btn[aria-pressed]::before{
  content:'';
  position:absolute;
  left:.72rem;
  top:50%;
  width:.8rem;
  height:.8rem;
  margin-top:-.4rem;
  border:1.5px solid currentColor;
  border-radius:3px;
  opacity:.6;
}
.sk-btn[aria-pressed="true"]::before{background:currentColor;opacity:1}
.sk-btn[aria-pressed="true"]::after{
  content:'';
  position:absolute;
  left:1.005rem;
  top:50%;
  width:.24rem;
  height:.46rem;
  margin-top:-.3rem;
  border-right:2px solid var(--card-bg);
  border-bottom:2px solid var(--card-bg);
  transform:rotate(45deg);
}
/* Reference on a small screen (puzzle.js syncRefUi, .is-mini): the panel
   starts closed, and the button shows a thumbnail of the painting where
   the check box was (a disclosure button, aria-expanded). Outside
   .is-mini (large screens, the reference off, blind mode) the thumbnail
   is not shown: blind mode hides the painting completely. */
.sk-ref-mini{display:none}
.sk-ref-btn.is-mini{padding-left:.4rem}
.sk-ref-btn.is-mini .sk-ref-mini{display:block;flex:none;height:26px;border-radius:3px;overflow:hidden;box-shadow:0 0 0 1px var(--color-border-hover)}
.sk-ref-mini picture,.sk-ref-mini img{display:block;width:auto;height:26px}
.sk-ref-btn.is-mini[aria-expanded="true"]{border-color:var(--color-primary-ui);color:var(--color-primary-text);background:var(--color-primary-soft)}
/* Unavailable but still in the toolbar's arrow-key order (Shuffle once the puzzle is complete) */
.sk-btn[aria-disabled="true"],.sk-btn[aria-disabled="true"]:hover{opacity:.5;cursor:not-allowed;border-color:var(--color-border-hover);background:var(--card-bg)}
/* Completion: the move count, and the button that opens the result card
   again (puzzle.js section 11d). A small card shape marks it as one. */
.sk-done{background:var(--color-primary-soft);color:var(--color-primary-text);font-weight:600}
button.sk-done{
  border:1px solid var(--color-primary-ui);
  font-family:'Outfit','Noto Sans JP',system-ui,sans-serif;
  cursor:pointer;
  transition:background .2s var(--ease-breathe);
}
button.sk-done::after{content:'';flex:none;width:14px;height:10px;border:1.5px solid currentColor;border-radius:2px}
button.sk-done:hover{background:var(--color-primary-highlight)}
button.sk-done:focus-visible{outline:2px solid var(--color-primary-ui);outline-offset:2px;box-shadow:none}
/* Timer (puzzle.js section 11c): fixed-width digits, so it never jiggles */
.sk-time #sk-time{display:inline-block;min-width:2.9rem;font-variant-numeric:tabular-nums;color:var(--color-text);font-weight:600;text-align:center}
.sk-btn-icon{width:34px;padding:0;font-size:1.15rem}
/* Main action in a dialog (filled) and a quiet one */
.sk-btn-primary{border-color:transparent;background:var(--color-primary-ui);color:var(--btn-text);font-weight:600}
.sk-btn-primary:hover{border-color:transparent;background:var(--color-primary-hover);color:var(--btn-text)}
.sk-btn-quiet{border-color:transparent;background:transparent;color:var(--color-text-secondary)}
.sk-btn-quiet:hover{border-color:var(--color-border-hover);background:var(--color-surface-alt);color:var(--color-text)}

/* ── Tier picker: a menu button (it replaces the tier chip) and its menu.
      puzzle.js lists the tiers this screen offers (< 900 px: Petal and
      Branch only). The check mark shows the tier being played. ── */
.sk-tierpick{position:relative}
.sk-tier-btn{gap:.55rem;padding:0 .75rem 0 .9rem;border-radius:999px;border-color:transparent;background:var(--color-surface-alt);white-space:nowrap}
.sk-tier-btn strong{font-weight:600;color:var(--color-text)}
.sk-caret{width:.45rem;height:.45rem;margin-top:-.2rem;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(45deg);opacity:.75}
.sk-tier-btn[aria-expanded="true"] .sk-caret{margin-top:.25rem;transform:rotate(225deg)}
.sk-pop{
  position:absolute;
  top:calc(100% + 6px);
  left:0;
  z-index:20; /* over the stage's panels (z-index 1-3) */
  min-width:17.5rem;
  max-width:calc(100vw - 2rem);
  padding:.35rem;
  border-radius:12px;
  background:var(--color-surface);
  border:1px solid var(--color-border-hover);
  box-shadow:var(--shadow-soft-2);
}
.sk-tier-menu{list-style:none;margin:0;padding:0}
.sk-tier-menu [role="menuitemradio"]{
  position:relative;
  display:grid;
  grid-template-columns:1fr auto; /* name (wraps in its column), count */
  align-items:baseline;
  gap:.1rem 1rem;
  min-height:40px;
  padding:.6rem .8rem .6rem 2.1rem;
  border-radius:8px;
  color:var(--color-text);
  font-size:.9rem;
  line-height:1.3;
  cursor:pointer;
  outline:none;
}
.sk-tier-menu [role="menuitemradio"]:hover{background:var(--color-surface-alt)}
.sk-tier-menu [role="menuitemradio"]:focus{background:var(--color-primary-highlight)}
.sk-tier-menu [role="menuitemradio"]:focus-visible{outline:2px solid var(--color-primary-ui);outline-offset:-2px}
.sk-tier-menu [aria-checked="true"]{font-weight:600}
.sk-tier-menu [aria-checked="true"]::before{
  content:'';
  position:absolute;
  left:.85rem;
  top:50%;
  width:.35rem;
  height:.7rem;
  border-right:2px solid var(--color-primary-ui);
  border-bottom:2px solid var(--color-primary-ui);
  transform:translateY(-65%) rotate(45deg);
}
.sk-tier-count{color:var(--color-text-secondary);font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap}
/* Another tier's saved game (puzzle.js syncTierUi): its own line */
.sk-tier-saved{grid-column:1 / -1;font-size:.8rem;font-weight:500;color:var(--color-primary-text);font-variant-numeric:tabular-nums}
.sk-tier-note{margin:.3rem .8rem .35rem;font-size:.8rem;line-height:1.4;color:var(--color-text-secondary)}

/* ── Bar + table: together they fill the screen below the nav at the
      top of the page, however many lines the toolbar wraps to ── */
.sk-play{
  display:flex;
  flex-direction:column;
  min-height:calc(100vh - 64px);
  min-height:calc(100dvh - 64px);
}
.sk-bar{flex:none}

/* ── Stage ── */
/* The table row (.sk-table): the table (.sk-stage) and, on large screens,
   the reference image in a column beside it. At least 520 px tall, but
   never more than the screen less 65 px (the nav's height and its
   border), so the whole table at Fit can be seen at once (owner,
   2026-10-01: "nothing ever covers a piece"): on a short screen (a phone
   held sideways, a 568 px phone, a short window) the page scrolls by the
   bar's height and the table then fills the screen. svh, the height with
   a phone browser's own bars shown, does not change as its address bar
   comes and goes. */
.sk-table{
  position:relative;
  display:flex;
  flex:1 0 min(520px,calc(100vh - 65px)); /* fills the rest */
  flex:1 0 min(520px,calc(100svh - 65px));
  min-height:0;
  background:var(--sk-side);
}
.sk-stage{
  position:relative;
  flex:1 1 0;
  min-width:0;
  background:var(--sk-surround);
  overflow:hidden;
  touch-action:none;
  user-select:none;
  -webkit-user-select:none;
  -webkit-touch-callout:none;
  -webkit-tap-highlight-color:transparent;
  overscroll-behavior:contain;
}
.sk-stage:focus{outline:none}
/* Painted above the canvases, which cover the stage's own background.
   puzzle.js sets .is-kbd-focus only when the stage was reached by keyboard
   (:focus-visible would also light up at a Space-pan after a click). */
.sk-stage.is-kbd-focus::after{
  content:'';
  position:absolute;
  inset:0;
  z-index:1;
  box-shadow:inset 0 0 0 3px var(--sk-focus);
  pointer-events:none;
}
/* Layer canvases: puzzle.js sets each one's size (whole CSS px that are
   whole backing px, so the static layer can overhang the stage by a pixel;
   the stage clips it) and, for the sprite and effects, its position. */
.sk-layer{position:absolute;left:0;top:0;width:100%;height:100%;display:block}
.sk-static{cursor:default}
/* Dragged-group sprite: never takes the pointer */
.sk-dynamic{width:1px;height:1px;pointer-events:none;will-change:transform}
/* Effects (snap feedback, petals): 1x1 px when idle, never takes the pointer */
.sk-fx{width:1px;height:1px;pointer-events:none}
/* Selected group while the table is used from the keyboard (N, arrow keys,
   R): puzzle.js sets its size and position over the group's cells.
   A dashed box with a dark halo, so shape and colour both mark it. */
.sk-sel{
  position:absolute;
  left:0;
  top:0;
  z-index:1;
  pointer-events:none;
  border:2px dashed var(--sk-focus);
  border-radius:6px;
  box-shadow:0 0 0 1px rgba(0,0,0,.6),inset 0 0 0 1px rgba(0,0,0,.6);
}

/* Reference image. Large screens: in a column right of the table, never
   over it (owner, 2026-10-01: "nothing ever covers a piece"); shown while
   the reference is on, and the table is that much narrower. Small screens
   (the rule puzzle.js calls narrowScreen, the same two media queries): it
   starts closed, and the player opens it over the table's top right from
   the toolbar's Reference button (puzzle.js syncRefUi). */
.sk-ref{
  flex:none;
  align-self:flex-start;
  margin:12px;
  width:clamp(112px,12vw,180px);
  padding:6px;
  border-radius:10px;
  background:var(--sk-panel);
  border:1px solid rgba(255,255,255,.12);
  box-shadow:0 8px 24px rgba(0,0,0,.35);
  color:var(--sk-panel-text);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);
}
.sk-ref-head{display:flex;align-items:center;justify-content:space-between;gap:.25rem;padding:0 2px 5px 4px}
.sk-ref-head span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.7rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--sk-panel-dim)}
.sk-ref-hide{
  display:inline-flex;align-items:center;justify-content:center;
  flex:none; /* never squeezed by the label */
  width:24px;height:24px;border-radius:6px;border:0;
  background:transparent;color:var(--sk-panel-dim);cursor:pointer;font-size:1rem;line-height:1;
}
@media (max-width:899.98px),(pointer:coarse) and (max-height:599.98px){
  .sk-ref{position:absolute;top:12px;right:12px;z-index:2;margin:0}
}
/* A narrow panel: no label, and a 36 px × in the panel's top right
   corner, over its padding. The label and the 24 px × side by side need
   108 px inside the panel (the label is 73.4 px in Outfit), which a panel
   has from 122 px wide (a 1,017 px window); the 96 px phone panel, the
   112 px one on a phone held sideways and the panels of 900-1,016 px
   windows (112-122 px) take this form. There the × is one of the two ways
   to close the panel (the Reference button is the other). The figure keeps
   its name, "Reference image". A wider panel whose label still does not
   fit (a fallback font) cuts the label short; the × keeps its size. */
.sk-ref{container-type:inline-size}
@container (max-width:108px){
  .sk-ref-head{justify-content:flex-end;padding:0 0 2px}
  .sk-ref-head span{display:none}
  .sk-ref-hide{width:36px;height:36px;margin:-6px -6px 0 0;font-size:1.25rem}
}
.sk-ref-hide:hover{background:rgba(255,255,255,.1);color:var(--sk-panel-text)}
.sk-ref-hide:focus-visible{outline:2px solid #c4b5fd;outline-offset:1px;box-shadow:none}
.sk-ref picture,.sk-ref img{display:block;width:100%;height:auto;border-radius:4px}

/* Nothing of the page lies over the table (owner, 2026-10-01: "nothing
   ever covers a piece"), apart from what the player opens on purpose
   (the reference panel on a small screen, the tier menu, the dialogs).
   The resume banner sits above the bar, the table's messages on a line
   between the bar and the table, the reference on a large screen in a
   column beside it, and the site nav scrolls away with the page. When the
   banner or the message line comes or goes, only the table's top edge
   moves, and when the column does, its right edge; puzzle.js (resize)
   keeps the pieces where they are on the page. */

/* No scroll anchoring on this page (puzzle.css is loaded by /art/play
   alone). Chrome's anchoring, also as it puts the scroll back on its own
   Reload or Back, moved the page down by the banner's height as the
   banner arrived, so the banner opened out of view (under the nav, when
   it was fixed here). puzzle.js keeps the pieces in place on the page
   itself (changeAbove), and brings the banner into view when a restored
   scroll leaves it above the screen while the player is at the table
   (revealResume). Chrome reads it from body for the page's own scroll. */
html:has(.sk-app),html:has(.sk-app) body{overflow-anchor:none}

/* Resume banner (puzzle.js section 11c): the saved game is on the table
   below it; the timer waits for Resume or Start over. Shown first (order)
   but kept after the bar in the source, so its place in the Tab order is
   unchanged: after the toolbar, just before the table. */
.sk-resume{
  order:-1;
  flex:none;
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:space-between;
  gap:10px 1.5rem;
  padding:11px clamp(1rem,3vw,2rem);
  background:var(--status-bg);
  border-bottom:1px solid var(--status-border);
  color:var(--color-text);
}
.sk-resume-text{min-width:0}
/* Line heights and spacing in whole px here and on the message line: the
   table below then starts on a whole pixel while they show, as it does
   once they go (a fractional start left the reference panel's caption
   rastered a fraction of a pixel off after the banner went). */
.sk-resume-title{margin:0;font-size:1rem;font-weight:600;line-height:21px}
.sk-resume-meta{margin:2px 0 0;font-size:.875rem;line-height:20px;color:var(--color-text-secondary);font-variant-numeric:tabular-nums}
.sk-resume-note{margin:2px 0 0;font-size:.875rem;line-height:20px;color:var(--status-text)}
.sk-resume-actions{display:flex;flex-wrap:wrap;gap:.5rem}
.sk-resume .sk-btn{height:40px;padding:0 1.05rem}

/* The table's messages: one line under the bar (puzzle.js section 11).
   Row 1: a short notice (a narrow screen's fallback tier, a link's game
   over a save). Row 2: the start hint until the first move, then, on
   tiers with the 24 px snapping floor, "Zoom in to place pieces" in the
   same place (.is-floor keeps that row, so the hint coming and going
   never resizes the table mid-game). With nothing to say it takes no
   room. Never takes the pointer. */
.sk-msgs{
  flex:none;
  display:grid;
  grid-template-columns:minmax(0,1fr);
  background:var(--color-surface);
  box-shadow:inset 0 -1px var(--color-border);
  pointer-events:none;
}
.sk-msgs.is-floor{grid-template-rows:auto minmax(32px,auto)}
.sk-msgs > p{
  margin:0;
  padding:6px clamp(1rem,3vw,2rem);
  font-size:.85rem;
  line-height:20px;
}
.sk-notice{grid-row:1;background:var(--status-bg);color:var(--status-text);font-weight:500}
.sk-hint,.sk-zoomhint{grid-row:2;grid-column:1;align-self:center}
.sk-hint{color:var(--color-text-secondary);transition:opacity .6s var(--ease-breathe)}
.sk-hint.is-quiet{opacity:0}
/* "Zoom in to place pieces": only while pieces are too small on screen to
   snap (puzzle.js noteSnapOff). Delayed so that on a first drop it fades
   in as the start hint, in the same place, fades out. */
.sk-zoomhint{
  color:var(--color-primary-text);
  font-weight:600;
  animation:sk-fade-in .3s var(--ease-breathe) .3s both;
}
@keyframes sk-fade-in{from{opacity:0}to{opacity:1}}

/* ── Dialogs (settings, confirmation): <dialog> with showModal. The
      dialog box has no padding, so a press on it is on the backdrop
      (puzzle.js closes it there). ── */
.sk-dialog{
  margin:auto; /* the core reset zeroes the UA's centring margin */
  padding:0;
  border:0;
  width:min(31rem,calc(100vw - 2rem));
  max-width:none; /* the UA's modal max-width would cap the phone layout */
  max-height:calc(100vh - 2rem);
  max-height:calc(100dvh - 2rem);
  border-radius:16px;
  background:var(--color-surface);
  color:var(--color-text);
  box-shadow:var(--shadow-soft-3);
  overflow:auto;
  overscroll-behavior:contain;
}
[data-theme="dark"] .sk-dialog{color-scheme:dark;border:1px solid var(--color-border-hover)}
.sk-dialog::backdrop{background:rgba(12,10,20,.55)}
.sk-dialog-sm{width:min(26rem,calc(100vw - 2rem))}
.sk-dialog-body{padding:1.2rem 1.35rem 1.1rem}
.sk-dialog-head{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:.2rem}
.sk-dialog h2{
  font-family:'Fraunces','Noto Sans JP',Georgia,serif;
  font-weight:700;
  font-size:1.3rem;
  line-height:1.2;
  letter-spacing:-.01em;
  color:var(--color-text);
}
.sk-dialog-x{
  display:inline-flex;align-items:center;justify-content:center;
  flex:none;width:40px;height:40px;margin-right:-.5rem;border-radius:8px;border:0;
  background:transparent;color:var(--color-text-secondary);font-size:1.5rem;line-height:1;cursor:pointer;
}
.sk-dialog-x:hover{background:var(--color-surface-alt);color:var(--color-text)}
.sk-dialog button:focus-visible,.sk-dialog input:focus-visible{outline:2px solid var(--color-primary-ui);outline-offset:2px;box-shadow:none}
.sk-dialog-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:.5rem;margin-top:1.1rem}
.sk-dialog-foot .sk-btn{height:40px}
.sk-dialog-foot .sk-btn-quiet{margin-right:auto;padding:0 .6rem}
/* Settings: the foot sticks to the bottom of the dialog, which scrolls on
   screens under ~800 px tall, so Done is always in view. It spans the
   dialog's width (the body's padding, taken back) on its own ground. */
.sk-dialog-foot-stick{
  position:sticky;
  bottom:0;
  z-index:1;
  margin:1.1rem -1.35rem -1.1rem;
  padding:.75rem 1.35rem 1.1rem;
  background:var(--color-surface);
  border-top:1px solid var(--color-border-hover);
}
/* Keyboard focus is never left under that foot (WCAG 2.4.11): the browser
   counts a control under it as in view and would not scroll. Scroll
   padding keeps what gets focus (and what puzzle.js scrolls to) clear of
   the foot, 4.4rem tall on one row (4.2rem on a phone), with room for the
   focus ring, and clear of the top edge by the ring. */
.sk-dialog{scroll-padding:.5rem 0}
.sk-dialog:has(.sk-dialog-foot-stick){scroll-padding-bottom:5.5rem}
.sk-confirm-text{margin:.6rem 0 0;font-size:.95rem;line-height:1.5;color:var(--color-text-secondary)}
.sk-dialog a:focus-visible{outline:2px solid var(--color-primary-ui);outline-offset:2px;box-shadow:none}

/* Result card (puzzle.js section 11d): the PNG's preview at the dialog's
   width (its own 1200:630 shape, held while it is drawn), then the
   actions, which wrap into rows on a phone. */
.sk-card{width:min(44rem,calc(100vw - 2rem))}
.sk-card-sum{margin:.1rem 0 .9rem;font-size:.95rem;line-height:1.5;color:var(--color-text-secondary)}
.sk-card-preview{position:relative;aspect-ratio:1200 / 630;border-radius:10px;overflow:hidden;background:#15111c;box-shadow:0 0 0 1px var(--color-border-hover)}
.sk-card-preview img{display:block;width:100%;height:auto}
.sk-card-wait{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;margin:0;padding:1rem;text-align:center;font-size:.95rem;color:#d2c9e2}
.sk-card-actions{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:1rem}
.sk-card-actions .sk-btn{flex:1 1 auto;height:auto;min-height:44px;padding:.55rem 1.1rem;line-height:1.25;text-align:center;text-decoration:none}
.sk-card-actions a.sk-btn:hover{color:var(--color-text)}
/* The CTAs: the scarf (primary), the prints, the championship */
.sk-card-ctas{margin-top:.5rem}
.sk-card-actions a.sk-btn-primary:hover{color:var(--btn-text)}
.sk-card-status{min-height:1.4em;margin:.75rem 0 0;font-size:.9rem;line-height:1.4;color:var(--status-text);overflow-wrap:anywhere}

.sk-set-tier{margin:0 0 .9rem;font-size:.875rem;line-height:1.45;color:var(--color-text-secondary)}
.sk-set-group{margin:0;padding:.85rem 0 .35rem;border:0;border-top:1px solid var(--color-border-hover);min-width:0}
.sk-set-group legend{float:left;width:100%;margin-bottom:.2rem;padding:0;font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--color-text-secondary)}
.sk-set-group legend + *{clear:both}
.sk-set-row{display:grid;grid-template-columns:auto 1fr;align-items:center;gap:0 .7rem;padding:.1rem 0 .35rem;min-height:44px}
.sk-set-row input[type="checkbox"]{width:1.2rem;height:1.2rem;margin:0;accent-color:var(--color-primary-ui);cursor:pointer}
.sk-set-row label{padding:.5rem 0 .3rem;font-size:.95rem;font-weight:500;line-height:1.35;color:var(--color-text);cursor:pointer} /* padded: a 32 px target */
.sk-set-note{grid-column:2;margin:0;font-size:.82rem;line-height:1.4;color:var(--color-text-secondary)}
.sk-set-range{grid-template-columns:1fr auto}
.sk-set-range output{font-size:.9rem;font-weight:600;font-variant-numeric:tabular-nums;color:var(--color-text-secondary)}
.sk-set-range input[type="range"]{grid-column:1 / -1;width:100%;height:28px;margin:0;accent-color:var(--color-primary-ui);cursor:pointer}
.sk-set-range .sk-set-note{grid-column:1 / -1}
/* Blind mode: the reference and ghost controls are off (disabled) */
.sk-set-row.is-off label,.sk-set-row.is-off output{opacity:.55;cursor:default}
.sk-set-row input:disabled{cursor:not-allowed}
.sk-set-pending{margin:.45rem 0 .4rem;padding:.75rem .85rem .85rem;border-radius:10px;background:var(--status-bg);border:1px solid var(--status-border)}
.sk-set-applies{margin:0 0 .3rem;font-size:.9rem;font-weight:600;color:var(--status-text)}
.sk-set-risk{margin:0 0 .3rem;font-size:.85rem;line-height:1.4;color:var(--color-text-secondary)}
.sk-set-pending .sk-btn{margin-top:.35rem;height:auto;min-height:40px;padding:.5rem .9rem;line-height:1.25;text-align:left}
.sk-set-keys{padding-top:.85rem;border-top:1px solid var(--color-border-hover)}
.sk-set-keys h3{margin:0 0 .15rem;font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--color-text-secondary)}
.sk-set-keys .sk-set-note{margin-bottom:.45rem}
.sk-set-keys dl{display:grid;grid-template-columns:auto 1fr;gap:.35rem .9rem;margin:0;font-size:.85rem;line-height:1.4}
.sk-set-keys dt{white-space:nowrap;color:var(--color-text)}
.sk-set-keys dd{margin:0;color:var(--color-text-secondary)}
.sk-set-keys kbd{
  display:inline-block;min-width:1.5em;padding:0 .35em;border-radius:5px;
  border:1px solid var(--color-border-hover);border-bottom-width:2px;background:var(--color-surface-alt);
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.8em;line-height:1.5;text-align:center;color:var(--color-text);
}

/* Loading and error overlay */
.sk-status{
  position:absolute;
  inset:0;
  z-index:3;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:.9rem;
  padding:1.5rem;
  text-align:center;
  background:var(--sk-surround);
  color:var(--sk-panel-text);
}
.sk-status p{font-size:.95rem;max-width:34rem}
.sk-status.is-error p{color:#f3c6b8}
.sk-progress{width:min(240px,60%);height:3px;border-radius:2px;background:rgba(255,255,255,.12);overflow:hidden}
.sk-progress span{display:block;height:100%;width:0;background:#b9a4f5;transition:width .15s linear}

/* ── Below the table: the page copy, then the championship notify form;
      side by side from 960 px. One band, its columns centred within
      70rem. ── */
.sk-below{
  display:grid;
  grid-template-columns:minmax(0,1fr);
  padding:0 max(clamp(1rem,3vw,2rem),calc((100% - 70rem) / 2));
  background:var(--color-surface);
  border-top:1px solid var(--color-border);
}
.sk-copy{padding:clamp(2rem,5vw,3rem) 0}
.sk-copy > *{max-width:40rem}
.sk-copy h2{
  margin:0 0 .6rem;
  font-family:'Fraunces','Noto Sans JP',Georgia,serif;
  font-weight:700;
  font-size:1.5rem;
  line-height:1.2;
  letter-spacing:-.01em;
  color:var(--color-text);
}
.sk-copy h3{
  margin:1.5rem 0 .4rem;
  font-family:'Fraunces','Noto Sans JP',Georgia,serif;
  font-weight:700;
  font-size:1.15rem;
  line-height:1.25;
  color:var(--color-text);
}
.sk-copy p{margin:0;font-size:1rem;line-height:1.7;color:var(--color-text-secondary)}
.sk-copy cite{font-style:italic}
.sk-copy a{text-decoration:underline;text-underline-offset:2px}
.sk-copy a:focus-visible{outline:2px solid var(--color-primary-ui);outline-offset:2px;box-shadow:none}
/* The image credit under the heading: the title and the artist */
.sk-copy .sk-credit{margin:0 0 .75rem;font-size:.875rem;line-height:1.5;color:var(--color-text-secondary)}
.sk-copy .sk-copy-links{margin-top:.6rem}
/* The page's CTAs, after the painting's paragraph: the scarf (primary), the prints */
.sk-ctas{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:1.1rem}
.sk-copy .sk-ctas a.sk-btn{height:auto;min-height:44px;padding:.6rem 1.2rem;font-size:.95rem;line-height:1.25;text-align:center;text-decoration:none}
.sk-copy .sk-ctas a.sk-btn:hover{color:var(--color-text)}
.sk-copy .sk-ctas a.sk-btn-primary,.sk-copy .sk-ctas a.sk-btn-primary:hover{color:var(--btn-text)}

/* ── Championship notify form. Posts to Formspree without JavaScript;
      puzzle.js sends it with fetch and shows the result inline
      (bindNotify). The result card's CTA scrolls it to the top of the
      screen (the nav scrolls with the page here, so no scroll padding is
      kept for it: above). ── */
.sk-notify{
  padding:clamp(2rem,5vw,3rem) 0;
  border-top:1px solid var(--color-border);
}
[data-theme="dark"] .sk-notify{color-scheme:dark} /* native checkbox and autofill follow the theme */
.sk-notify-inner{max-width:34rem}
@media (min-width:960px){
  .sk-below{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
  .sk-copy{padding-right:clamp(2rem,4vw,3.5rem)}
  .sk-notify{border-top:0;border-left:1px solid var(--color-border);padding-left:clamp(2rem,4vw,3.5rem)}
}
.sk-notify h2{
  margin:0 0 .4rem;
  font-family:'Fraunces','Noto Sans JP',Georgia,serif;
  font-weight:700;
  font-size:1.35rem;
  line-height:1.2;
  letter-spacing:-.01em;
  color:var(--color-text);
}
.sk-notify-lede{margin:0 0 1.25rem;font-size:.95rem;line-height:1.5;color:var(--color-text-secondary)}
.sk-notify-form{display:grid;gap:1rem}
.sk-notify-field{display:grid;gap:.4rem}
.sk-notify-field label{font-size:.875rem;font-weight:600;color:var(--color-text)}
.sk-notify-field input{
  width:100%;
  height:44px;
  padding:0 .85rem;
  border-radius:var(--radius-sm,8px);
  border:1px solid var(--color-text-dim);
  background:var(--card-bg);
  color:var(--color-text);
  font-family:'Outfit','Noto Sans JP',system-ui,sans-serif;
  font-size:1rem; /* 16px: no zoom on focus in iOS Safari */
}
.sk-notify-optin{display:grid;grid-template-columns:auto 1fr;gap:.25rem .65rem;align-items:start}
.sk-notify-optin input{width:1.15rem;height:1.15rem;margin:.15rem 0 0;accent-color:var(--color-primary-ui);cursor:pointer}
.sk-notify-optin label{font-size:.9rem;line-height:1.45;color:var(--color-text);cursor:pointer}
.sk-notify-note{grid-column:2;margin:0;font-size:.85rem;line-height:1.45;color:var(--color-text-secondary)}
.sk-notify-note a{text-decoration:underline;text-underline-offset:2px}
.sk-notify-btn{
  justify-self:start;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-height:44px;
  padding:0 1.4rem;
  border:0;
  border-radius:var(--radius-sm,8px);
  background:var(--color-primary-ui);
  color:var(--btn-text);
  font-family:'Outfit','Noto Sans JP',system-ui,sans-serif;
  font-size:.95rem;
  font-weight:600;
  cursor:pointer;
  transition:background .2s var(--ease-breathe);
}
.sk-notify-btn:hover{background:var(--color-primary-hover)}
.sk-notify-btn:disabled{opacity:.65;cursor:progress}
.sk-notify-field input:focus-visible,
.sk-notify-optin input:focus-visible,
.sk-notify-btn:focus-visible,
.sk-notify-note a:focus-visible{outline:2px solid var(--color-primary-ui);outline-offset:2px;box-shadow:none}
.sk-notify-status{min-height:1.45em;margin:0;font-size:.9rem;line-height:1.45}
.sk-notify-status.is-ok{color:var(--status-text)}
.sk-notify-status.is-error{color:#b42318}
[data-theme="dark"] .sk-notify-status.is-error{color:#f4a397}
/* Honeypot: off screen, out of the tab order and hidden from assistive tech */
.sk-notify-gotcha{position:absolute!important;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden}

.sk-footer-credit{margin:0 0 1.25rem;font-size:.8rem}

@media (max-width:900px){
  .sk-title h1{font-size:1.25rem}
}
@media (max-width:899.98px){
  .sk-ref{width:96px} /* the small-screen panel (a 900 px window has the column) */
}
@media (max-width:520px){
  /* Phone: the dialog nearly fills the screen; the key list stacks */
  .sk-dialog{width:calc(100vw - 1rem);max-height:calc(100dvh - 1rem);border-radius:14px}
  .sk-dialog-body{padding:1rem 1rem .9rem}
  .sk-set-keys dl{grid-template-columns:1fr;gap:.1rem}
  .sk-set-keys dd{margin-bottom:.35rem}
  .sk-dialog-foot-stick{margin:1rem -1rem -.9rem;padding:.7rem 1rem .9rem}
  /* The tier, seed and timer on one row: the seed's word is for screen
     readers only here (the chip's title still says what it is) */
  .sk-seed-word{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}
  .sk-chip{padding:0 .7rem}
  .sk-pop{min-width:min(17.5rem,calc(100vw - 2rem))}
}
@media (prefers-reduced-motion:reduce){
  .sk-hint,.sk-progress span,.sk-notify-btn{transition:none}
  .sk-zoomhint{animation:none}
}
