/* Hexart studio. Step one — the museum hang: two grown specimens hang side
   by side and the choice is made by looking. Step two — the drafting sheet
   as an infinite cloth: the chalk lattice runs edge to edge, the stitchable
   window sits centered and brighter, and every control floats on the cloth.
   Two button voices only: the primary hex-type patch (terminal actions,
   flooded by a random specimen on hover) and the quiet secondary text
   action whose gold stitch sews in on intent. */

@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('../../assets/fonts/bricolage-grotesque-latin.woff2') format('woff2');
}

:root {
  --bg: #0A0A0C;
  --cream: #EAE5D8;
  --cream-soft: #D8D2C2;
  --gold: #E8A020;
  --gold-light: #F2BC49;
  --muted: #8A8578;
  --ink: #141208;
}

/* Crossing between rooms is a dissolve, not a jump — the cloth persists. */
@view-transition {
  navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.45s;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg);
  color: var(--cream);
  font-family: 'Bricolage Grotesque', system-ui, -apple-system, sans-serif;
  overflow: hidden;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.stage {
  position: fixed;
  inset: 0;
}

/* The cloth's own night: star-dust behind the hung specimens. */
#dust {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

/* The gallery light. It warms toward the specimen the visitor chooses —
   never following the cursor. */
@property --glow-x {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 50%;
}

@property --glow-y {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 40%;
}

.glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  background: radial-gradient(ellipse 58% 44% at var(--glow-x, 50%) var(--glow-y, 40%),
    rgba(232, 160, 32, 0.09),
    rgba(232, 160, 32, 0.03) 48%,
    transparent 72%);
  transition: --glow-x 2.6s ease-in-out, --glow-y 2.6s ease-in-out, opacity 1.4s ease;
}

/* Light falling off at the bottom of the frame so the chrome reads. */
.hem {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 30vh;
  pointer-events: none;
  background: linear-gradient(to top,
    rgba(10, 10, 12, 0.82),
    rgba(10, 10, 12, 0.32) 48%,
    transparent);
}

.mono {
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
}

@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes stitch-in {
  from {
    clip-path: inset(-2px 100% -2px 0);
  }
  to {
    clip-path: inset(-2px 0 -2px 0);
  }
}

@keyframes stitch-crawl {
  to {
    stroke-dashoffset: -8.6;
  }
}

/* ————— the two button voices ————— */

/* Secondary — the primary's quiet sibling: no box, no fill, no bulk.
   A mono word marked by a tiny hexagon cell, resting on a faint running
   stitch, standing at the primary's height so rows align as one family.
   Intent pulls the thread: gold-light, the cell takes the light, the
   dashes crawl. A held state (pressed/checked) keeps the thread at full. */
.inline-act {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 30px;
  margin: 0;
  padding: 0 2px;
  border: none;
  background: none;
  pointer-events: auto;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  color: var(--gold);
  text-decoration: none;
  cursor: pointer;
  transition: color 0.25s ease-out, text-shadow 0.25s ease-out;
}

@keyframes dash-crawl {
  to {
    background-position: -8.6px 0;
  }
}

/* Each option is marked by a cell of its own: a tiny hexagon that takes
   the light on hover and holds it while chosen. */
.inline-act::before {
  content: '';
  width: 6px;
  height: 7px;
  background: currentColor;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  opacity: 0.35;
  transition: opacity 0.25s ease-out;
}

.inline-act::after {
  content: '';
  position: absolute;
  left: 2px;
  right: 2px;
  bottom: 1px;
  height: 2px;
  background-image: repeating-linear-gradient(90deg,
    currentColor 0 5px, transparent 5px 8.6px);
  opacity: 0.32;
  transition: opacity 0.25s ease-out;
}

.inline-act:hover::before,
.inline-act[aria-pressed="true"]::before,
.inline-act[aria-checked="true"]::before {
  opacity: 1;
}

.inline-act:hover {
  color: var(--gold-light);
  text-shadow: 0 0 14px rgba(232, 160, 32, 0.4);
}

.inline-act:hover::after {
  opacity: 0.95;
  animation: dash-crawl 1.1s linear infinite;
}

.inline-act[aria-pressed="true"],
.inline-act[aria-checked="true"] {
  color: var(--gold-light);
}

.inline-act[aria-pressed="true"]::after,
.inline-act[aria-checked="true"]::after {
  opacity: 0.95;
}

.inline-act:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 3px;
  border-radius: 2px;
}

.inline-act:disabled {
  color: var(--muted);
  cursor: default;
  text-shadow: none;
}

.inline-act:disabled::after {
  content: none;
}

/* An armed destructive action asks first, in its own words. */
.inline-act.confirming {
  color: var(--gold-light);
}

.inline-act.confirming::after {
  opacity: 0.95;
  animation: dash-crawl 1.1s linear infinite;
}

/* Ways back and micro-radios drop the marker cell; the stitch alone
   carries them. */
.inline-act.no-dot::before {
  content: none;
}

/* Primary — the hex-type patch. Built by hex-button.js: the label is
   bitmap-font words as mosaic cells, the border a running stitch, and a
   hover floods the patch with a randomly-seeded specimen. */
.cta-hex {
  position: relative;
  margin: 0;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: rgba(234, 229, 216, 0.035);
  cursor: pointer;
  overflow: hidden;
  box-shadow: 0 8px 26px rgba(232, 160, 32, 0.14);
  transition: box-shadow 0.3s ease-out, transform 0.2s ease-out;
}

.cta-hex:hover {
  box-shadow: 0 14px 40px rgba(232, 160, 32, 0.3);
}

.cta-hex:active {
  transform: translateY(1px);
  box-shadow: 0 6px 20px rgba(232, 160, 32, 0.2);
}

.cta-hex:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 4px;
}

.cta-hex canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.cta-flood {
  opacity: 0;
  transition: opacity 0.42s ease-out;
}

.cta-hex.is-flooding .cta-flood {
  opacity: 1;
  transition: opacity 0.16s ease-out;
}

/* The word holds through the flood: the cream label stays pinned above
   the specimen, exactly over the design's own mask cells. */
.cta-patch {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.cta-patch rect {
  x: 1.5px;
  y: 1.5px;
  width: calc(100% - 3px);
  height: calc(100% - 3px);
  rx: 5px;
  fill: none;
  stroke: var(--gold);
  stroke-width: 1.5;
  stroke-dasharray: 5 3.6;
  opacity: 0.55;
  transition: opacity 0.25s ease-out, stroke 0.25s ease-out;
}

.cta-hex:hover .cta-patch rect {
  opacity: 1;
  stroke: var(--gold-light);
  animation: stitch-crawl 1.1s linear infinite;
}

/* ————— chrome sewn to the corners ————— */

/* The way back to the front room — an anchor in the secondary voice,
   sewn top-left. */
.home {
  position: absolute;
  top: clamp(10px, 2.2vh, 26px);
  left: clamp(14px, 2.7vw, 40px);
  padding: 8px 2px 10px;
  color: var(--gold);
  text-decoration: none;
  transition: color 0.25s ease-out;
  animation: rise-in 0.9s cubic-bezier(0.16, 1, 0.3, 1) 0.9s both;
}

.home::after {
  content: '';
  position: absolute;
  left: 2px;
  right: 2px;
  bottom: 5px;
  height: 2px;
  background-image: repeating-linear-gradient(90deg,
    currentColor 0 5px, transparent 5px 8.6px);
  opacity: 0.32;
  transition: opacity 0.25s ease-out;
}

.home:hover {
  color: var(--gold-light);
  text-shadow: 0 0 14px rgba(232, 160, 32, 0.4);
}

.home:hover::after {
  opacity: 0.95;
  animation: dash-crawl 1.1s linear infinite;
}

.home:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 3px;
  border-radius: 2px;
}

/* The living brand — the woven HEXART at center top, the way home on
   every page. The canvas re-threads itself quietly (src/app/logo.js). */
.brand {
  position: absolute;
  top: 14px;
  /* centered by margins, never by transform — rise-in owns transform
     and its fill would pin the offset (the lede lesson, again) */
  inset-inline: 0;
  margin-inline: auto;
  width: fit-content;
  z-index: 5;
  display: block;
  line-height: 0;
  border-radius: 2px;
  animation: rise-in 0.9s cubic-bezier(0.16, 1, 0.3, 1) 0.35s both;
}

.brand canvas {
  display: block;
}

.brand:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 4px;
}

/* ————— the hang ————— */

/* Full-viewport layout containers must not swallow the pointer — only the
   things inside them that can be acted on take it. */
.hang {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(32px, 6vw, 96px);
  padding: 0 24px;
  transform: translateY(-1.5vh);
  pointer-events: none;
}

.specimen-block {
  display: flex;
  flex-direction: column;
}

.specimen {
  display: block;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  pointer-events: auto;
}

.specimen:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 6px;
}

.spec-art {
  display: block;
  height: min(50vh, 440px);
  aspect-ratio: 760 / 860;
  transition: filter 0.45s ease;
}

/* The unchosen specimen falls into shadow; the chosen one keeps the light. */
.specimen.is-dim .spec-art {
  filter: brightness(0.58) saturate(0.85);
}

.specimen:hover .spec-art {
  filter: brightness(1.06);
}

.specimen.is-dim:hover .spec-art {
  filter: brightness(0.78) saturate(0.92);
}

/* Museum label beneath each frame. Hung (revealed) as its specimen grows. */
.spec-placard {
  display: block;
  margin-top: 14px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

.specimen.hung .spec-placard {
  opacity: 1;
  transform: none;
}

.spec-title {
  position: relative;
  display: inline-block;
  padding: 0 2px 9px;
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: 0.005em;
  color: var(--cream-soft);
  transition: color 0.3s ease-out;
}

.specimen:hover .spec-title {
  color: var(--cream);
}

.specimen.is-chosen .spec-title {
  color: var(--cream);
}

/* Every actionable thing is gold (the One Gold Rule): each title rests on
   a faint running stitch — the sign it can be chosen — and the choice sews
   it in at full thread. */
.spec-title .stitch {
  position: absolute;
  left: 2px;
  right: 2px;
  bottom: 2px;
  width: calc(100% - 4px);
  height: 4px;
  overflow: visible;
  opacity: 0.35;
  transition: opacity 0.3s ease-out;
}

.spec-title .stitch line {
  stroke: var(--gold);
  stroke-width: 2;
  stroke-dasharray: 5 3.6;
}

.specimen:hover .spec-title .stitch {
  opacity: 0.6;
}

.specimen.is-chosen .spec-title .stitch {
  opacity: 1;
  animation: stitch-in 0.7s ease-out both;
}

/* Same size as the title — the label's hierarchy is weight and color. */
.spec-desc {
  display: block;
  font-size: 1.02rem;
  font-weight: 400;
  color: var(--muted);
  transition: color 0.3s ease-out;
}

.specimen.is-chosen .spec-desc {
  color: var(--cream-soft);
}

/* A line added to the label: how the mark will arrive. Space is reserved so
   the hang never shifts; the line surfaces when the marked specimen is
   chosen. Both blocks carry the spacer for symmetry. */
.spec-adds {
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: 44px;
  padding-top: 10px;
  visibility: hidden;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.4s ease-out, transform 0.4s ease-out, visibility 0s linear 0.4s;
}

.spec-adds.open {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition: opacity 0.4s ease-out 0.1s, transform 0.4s ease-out 0.1s, visibility 0s;
}

/* The hexagon markers carry the rhythm now; the old middots retire.
   Every action row separates its buttons by the same 18px thread. */
.adds-dot {
  display: none;
}

/* ————— the thread onward ————— */

.invite {
  position: absolute;
  inset-inline: 0;
  bottom: max(6.5vh, 44px);
  display: grid;
  justify-items: center;
  padding: 0 24px;
  text-align: center;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.16, 1, 0.3, 1), visibility 0s linear 0.5s;
}

.invite.armed {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.16, 1, 0.3, 1), visibility 0s;
}

.invite.armed > * {
  pointer-events: auto;
}

/* The flow's own placard, bottom-left: machine truth about where you are. */
.placard {
  position: absolute;
  left: clamp(18px, 3vw, 44px);
  bottom: clamp(16px, 3vh, 36px);
  margin: 0;
  color: var(--muted);
  line-height: 1.7;
  animation: rise-in 0.9s cubic-bezier(0.16, 1, 0.3, 1) 0.7s both;
}

#path-word {
  color: var(--cream-soft);
}

/* ————— the step change: the cloth is re-dyed, the room stays ————— */

.step-one .hang,
.step-one .invite {
  transition: opacity 0.45s ease, transform 0.45s ease;
}

.stage.leaving .hang,
.stage.leaving .invite {
  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;
}

.stage.stubbed .hang,
.stage.stubbed .invite {
  visibility: hidden;
}

/* The open label-line pins its own visibility — put it out explicitly
   when the step changes, or it would float alone over the stub. */
.stage.stubbed .spec-adds.open {
  visibility: hidden;
}

.stub {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  text-align: center;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
}

.stage.stubbed .stub {
  visibility: visible;
  opacity: 1;
  animation: rise-in 0.8s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.stub-inner {
  max-width: 44ch;
  pointer-events: auto;
}

.stub-line {
  margin: 0 0 18px;
  font-size: clamp(1.02rem, 0.9rem + 0.7vw, 1.3rem);
  font-weight: 500;
  line-height: 1.45;
  color: var(--cream-soft);
  text-wrap: balance;
}

.stub-line:focus {
  outline: none;
}

.noscript {
  position: absolute;
  top: 28px;
  inset-inline: 0;
  margin: 0 auto;
  max-width: 44ch;
  padding: 0 24px;
  text-align: center;
  font-size: clamp(1.02rem, 0.9rem + 0.7vw, 1.3rem);
  color: var(--muted);
}

/* ————— step two: the drafting sheet on the infinite cloth ————— */

/* Step one's chrome bows out entirely while the sheet is on the cloth. */
.stage.marking .hang,
.stage.marking #invite,
.stage.marking .home {
  visibility: hidden;
}

.stage.marking .spec-adds.open {
  visibility: hidden;
}

.atelier {
  position: absolute;
  inset: 0;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
}

.stage.marking:not(.stubbed) .atelier {
  visibility: visible;
  opacity: 1;
}

/* Only the things that can be acted on take the pointer; hidden layers are
   visibility-gated, which also removes them from reach. */
.atelier :is(button, input, #cloth) {
  pointer-events: auto;
}

/* A child that pins its own visibility (the armed invite, the open drop)
   would override a hidden ancestor and stay clickable in another room —
   so outside its room the whole sheet is made inert outright. */
.stage:not(.marking) .atelier,
.stage:not(.marking) .atelier *,
.stage.stubbed .atelier,
.stage.stubbed .atelier * {
  visibility: hidden !important;
  pointer-events: none !important;
}

.stage.marking:not(.stubbed) .atelier > * {
  animation: rise-in 0.8s cubic-bezier(0.16, 1, 0.3, 1) both;
}

/* No entrance for children that gate their own visibility or opacity —
   a fill-forwards keyframe would pin them shown forever. The cloth never
   rises either: the chalk sweep is its arrival. */
.stage.marking:not(.stubbed) .atelier :is(#cloth, .proof, .drop, .mark-invite, .word-float, .export-veil) {
  animation: none;
}

.stage.marking:not(.stubbed) .atelier .rail { animation-delay: 0.14s; }
.stage.marking:not(.stubbed) .atelier .mark-name { animation-delay: 0.2s; }
.stage.marking:not(.stubbed) .atelier .reads { animation-delay: 0.26s; }

.stage.leaving .atelier {
  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;
  transition: opacity 0.45s ease, transform 0.45s ease;
}

/* The infinite cloth: the canvas is the whole room. Focus is shown by the
   gold needle the sheet draws, not an outline around the viewport. */
#cloth {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  cursor: crosshair;
  touch-action: none;
}

#cloth:focus-visible {
  outline: none;
}

/* The way back into the previous room. */
.atelier-back {
  position: absolute;
  top: clamp(10px, 2.2vh, 26px);
  left: clamp(14px, 2.7vw, 40px);
}

/* The sheet speaks no sentence — the brand at center top and the chalk
   itself carry the room (owner ruling 2026-08-05: no page names). */

/* The mark's name, floating under the way back. */
.mark-name {
  position: absolute;
  top: clamp(52px, 8.6vh, 86px);
  left: clamp(14px, 2.7vw, 40px);
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  color: var(--muted);
}

.mark-name input {
  width: 14ch;
  margin: 0;
  padding: 2px 0 4px;
  border: none;
  border-bottom: 1px dotted rgba(232, 160, 32, 0.45);
  background: none;
  font: inherit;
  letter-spacing: inherit;
  color: var(--cream-soft);
}

.mark-name input::placeholder {
  color: var(--muted);
}

.mark-name input:hover {
  border-bottom-color: var(--gold);
}

.mark-name input:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 3px;
  border-radius: 2px;
}

/* The proof: the mark at stamp size, on the cloth and on paper. */
.proof {
  position: absolute;
  top: clamp(14px, 2.6vh, 30px);
  right: clamp(16px, 2.7vw, 40px);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  opacity: 0;
  transition: opacity 0.4s ease-out;
}

/* The proof appears once there is something to prove. */
.proof.has-work {
  opacity: 1;
}

.proof canvas {
  display: block;
  width: 38px;
  height: 38px;
}

#proof-light {
  border-radius: 2px;
}

/* The transfer invitation: laid over the bare chalk on the import path. */
.drop {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  gap: 6px;
  text-align: center;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.4s ease-out, visibility 0s linear 0.4s;
  pointer-events: none;
}

.drop.open {
  visibility: visible;
  opacity: 1;
  transition: opacity 0.4s ease-out, visibility 0s;
}

.drop.open .inline-act {
  pointer-events: auto;
}

.drop-line {
  margin: 0;
  font-size: clamp(1.02rem, 0.9rem + 0.7vw, 1.3rem);
  font-weight: 500;
  color: var(--cream-soft);
  text-wrap: balance;
}

/* ————— the rail: a toolbar made of the lattice's own cells ————— */

/* Centered by flex between fixed insets — never by transform: the
   entrance animation owns transform, and a fill-forwards keyframe would
   pin a translate forever. The container is a layout ghost; only its
   cells take the pointer. */
.rail {
  position: absolute;
  left: clamp(14px, 2.4vw, 36px);
  top: 112px;
  bottom: 88px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 12px;
  pointer-events: none;
}

.rail-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  pointer-events: none;
}

/* The three threads lie in a row; the paired actions sit two abreast. */
.rail-row {
  flex-direction: row;
  align-items: center;
  gap: 7px;
}

.rail-duo {
  display: grid;
  grid-template-columns: auto auto;
  gap: 5px 6px;
}

.rail-sep {
  width: 16px;
  height: 1px;
  background: rgba(234, 229, 216, 0.14);
}

/* One hexagon per control. Rest: chalk outline, cream-soft glyph.
   Hover: gold outline. Held (checked/pressed): the cell fills gold and
   the glyph prints in ink — the One Gold Rule made literal. */
.hexcell {
  position: relative;
  width: 38px;
  height: 44px;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
}

.hexcell .cell {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.hexcell .cell polygon {
  fill: transparent;
  stroke: rgba(234, 229, 216, 0.22);
  stroke-width: 1.3;
  transition: fill 0.22s ease-out, stroke 0.22s ease-out, filter 0.22s ease-out;
}

.hexcell .glyph {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 18px;
  height: 18px;
  transform: translate(-50%, -50%);
  color: var(--cream-soft);
  transition: color 0.22s ease-out;
}

.hexcell .glyph :is(path, circle, polygon) {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.hexcell .glyph .half {
  fill: currentColor;
  stroke: none;
}

.hexcell:hover .cell polygon {
  stroke: var(--gold);
}

.hexcell:hover .glyph {
  color: var(--cream);
}

.hexcell[aria-checked="true"] .cell polygon,
.hexcell[aria-pressed="true"] .cell polygon {
  fill: var(--gold);
  stroke: var(--gold);
  filter: drop-shadow(0 5px 14px rgba(232, 160, 32, 0.32));
}

.hexcell[aria-checked="true"] .glyph,
.hexcell[aria-pressed="true"] .glyph {
  color: var(--ink);
}

.hexcell:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 3px;
  border-radius: 2px;
}

.hexcell:disabled {
  cursor: default;
}

.hexcell:disabled .cell polygon {
  stroke: rgba(234, 229, 216, 0.09);
}

.hexcell:disabled .glyph {
  color: var(--muted);
  opacity: 0.45;
}

/* An armed destructive cell asks first — it holds gold-light and pulses
   while its question is open in the tooltip. */
@keyframes cell-ask {
  from { opacity: 0.7; }
  to { opacity: 1; }
}

.hexcell.confirming .cell polygon {
  stroke: var(--gold-light);
}

.hexcell.confirming .glyph {
  color: var(--gold-light);
  animation: cell-ask 0.55s ease-in-out infinite alternate;
}

/* The three threads: the hexagon IS the spool. The chosen one is ringed
   in gold; the others rest dimmer in the shadow. */
.hexthread {
  width: 32px;
  height: 37px;
}

.hexthread svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.hexthread .swatch {
  opacity: 0.6;
  transition: opacity 0.22s ease-out, transform 0.22s ease-out;
  transform-origin: 50% 50%;
}

.hexthread .ring {
  fill: none;
  stroke: var(--gold);
  stroke-width: 1.3;
  opacity: 0;
  transition: opacity 0.22s ease-out;
}

.hexthread:hover .swatch {
  opacity: 1;
}

.hexthread[aria-checked="true"] .swatch {
  opacity: 1;
  transform: scale(1.12);
}

.hexthread[aria-checked="true"] .ring {
  opacity: 1;
}

/* The word for the letters tool: floats beside the rail while the
   letters cell is held. */
.word-float {
  position: absolute;
  left: calc(clamp(14px, 2.4vw, 36px) + 118px);
  top: calc(50% - 16px);
  display: none;
  align-items: baseline;
  gap: 8px;
  color: var(--muted);
}

.word-float.open {
  display: inline-flex;
}

.word-float input {
  width: 9ch;
  margin: 0;
  padding: 2px 0 4px;
  border: none;
  border-bottom: 1px dotted rgba(232, 160, 32, 0.45);
  background: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: uppercase;
  color: var(--cream-soft);
}

.word-float input:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 3px;
  border-radius: 2px;
}

.word-sizes {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  margin-left: 4px;
}

/* ————— machine truth, bottom-right ————— */

.reads {
  position: absolute;
  right: clamp(16px, 2.7vw, 40px);
  bottom: clamp(16px, 3vh, 36px);
  display: flex;
  align-items: baseline;
  gap: 22px;
  color: var(--muted);
  white-space: nowrap;
}

.read {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
}

.read-value {
  color: var(--cream-soft);
}

.read-value.lint-open {
  color: var(--cream);
}

/* ————— export and the threads onward ————— */

.mark-invite {
  bottom: max(2.8vh, 20px);
  gap: 6px;
}

.export-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 18px;
}

.mark-invite .onward {
  display: flex;
  align-items: center;
  gap: 18px;
}

/* ————— the export sheet: a placard lifted off the cloth ————— */

/* The veil is the re-dye grammar standing still: the room sinks under
   ground-colored wash while the placard holds the light. */
.export-veil {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(10, 10, 12, 0.74);
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease-out, visibility 0s linear 0.3s;
}

.export-veil.open {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transition: opacity 0.3s ease-out, visibility 0s;
}

/* The placard: the cloth itself, lifted and hemmed with a running
   stitch — the primary patch's grammar at document scale. */
.export-sheet {
  width: min(92vw, 396px);
  padding: 22px 26px 20px;
  border-radius: 6px;
  background: var(--bg);
  --seam: rgba(232, 160, 32, 0.5);
  background-image:
    repeating-linear-gradient(90deg, var(--seam) 0 5px, transparent 5px 8.6px),
    repeating-linear-gradient(90deg, var(--seam) 0 5px, transparent 5px 8.6px),
    repeating-linear-gradient(180deg, var(--seam) 0 5px, transparent 5px 8.6px),
    repeating-linear-gradient(180deg, var(--seam) 0 5px, transparent 5px 8.6px);
  background-size: 100% 1.5px, 100% 1.5px, 1.5px 100%, 1.5px 100%;
  background-position: 0 0, 0 100%, 0 0, 100% 0;
  background-repeat: no-repeat;
}

.export-title {
  margin: 0 0 14px;
  color: var(--muted);
}

.export-preview {
  display: block;
  width: 116px;
  height: 116px;
  margin: 0 auto 10px;
}

.export-opts {
  display: grid;
  gap: 2px;
}

.opt-row {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* A row that does not apply to the chosen format steps back, and its
   radios step out of reach with it. */
.opt-row.na {
  visibility: hidden;
}

.opt-label {
  width: 7ch;
  flex: none;
  color: var(--muted);
}

.export-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-top: 16px;
}

/* SHARE: the code line and its two actions — the same mono/opt-row
   grammar as FORMAT/GROUND/INK/SIZE above it, a hairline dividing the
   file options from the pastable code (the cutting table's own SHARE
   group speaks this grammar first; the drafting sheet borrows it). */
.export-group-head {
  margin: 14px 0 6px;
  padding-top: 12px;
  border-top: 1px dashed rgba(234, 229, 216, 0.14);
  color: var(--muted);
}

.share-code {
  flex: 1;
  min-width: 0;
  padding: 6px 10px;
  border: 1px solid rgba(234, 229, 216, 0.09);
  border-radius: 2px;
  background: rgba(234, 229, 216, 0.02);
  color: var(--cream-soft);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.share-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin: 8px 0 0;
}

/* ————— tooltips: the sheet names its cells ————— */

.tip {
  position: fixed;
  z-index: 40;
  display: flex;
  align-items: baseline;
  gap: 9px;
  padding: 7px 11px 8px;
  background: rgba(10, 10, 12, 0.93);
  border: 1px solid rgba(234, 229, 216, 0.16);
  border-radius: 2px;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  color: var(--cream-soft);
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  translate: 0 4px;
  transition: opacity 0.18s ease-out, translate 0.18s ease-out, visibility 0s linear 0.18s;
}

.tip.open {
  visibility: visible;
  opacity: 1;
  translate: 0 0;
  transition: opacity 0.18s ease-out, translate 0.18s ease-out, visibility 0s;
}

.tip-key {
  font-family: inherit;
  color: var(--gold);
}

/* ————— narrow and short rooms ————— */

@media (max-width: 719px) {
  /* The rail lies down: a floating row above the export thread.
     Centered by auto margins, never by transform. */
  .rail {
    left: 0;
    right: 0;
    top: auto;
    bottom: 176px;
    width: fit-content;
    max-width: 94vw;
    margin-inline: auto;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    row-gap: 6px;
    gap: 8px;
  }

  .rail-group {
    flex-direction: row;
    align-items: center;
    gap: 5px;
  }

  .rail-duo {
    display: flex;
  }

  .rail-sep {
    width: 1px;
    height: 16px;
    align-self: center;
  }

  .hexcell {
    width: 34px;
    height: 39px;
  }

  .hexcell .glyph {
    width: 16px;
    height: 16px;
  }

  .hexthread {
    width: 30px;
    height: 34px;
  }

  .word-float {
    left: 0;
    right: 0;
    top: 148px;
    width: fit-content;
    margin-inline: auto;
  }

  .reads {
    right: 0;
    left: 0;
    bottom: auto;
    top: 118px;
    width: fit-content;
    margin-inline: auto;
    gap: 14px;
  }

  /* Touch has no resting needle to report. */
  .reads .read:has(#read-needle) {
    display: none;
  }

  .mark-name {
    top: 92px;
  }

  .proof {
    top: clamp(12px, 2vh, 22px);
  }

  .proof canvas {
    width: 30px;
    height: 30px;
  }

  .stage.marking .placard {
    visibility: hidden;
  }
}

/* A short room shrinks the rail's cells before anything overlaps. */
@media (min-width: 720px) and (max-height: 740px) {
  .rail {
    top: 104px;
    bottom: 72px;
    gap: 9px;
  }

  .hexcell {
    width: 32px;
    height: 37px;
  }

  .hexcell .glyph {
    width: 15px;
    height: 15px;
  }

  .hexthread {
    width: 28px;
    height: 32px;
  }
}

/* In a critically short room every floating pixel belongs to the sheet. */
@media (max-height: 480px) {
  .stage.marking .placard {
    visibility: hidden;
  }

  .mark-name {
    visibility: hidden;
  }
}

@media (max-width: 640px) {
  .hang {
    flex-direction: column;
    align-items: center;
    gap: 16px;
    /* The stacked hang keeps clear of the spoken question above and
       leaves the bottom band to the rising Continue. */
    padding: 96px 24px 88px;
  }

  .specimen-block {
    align-items: center;
  }

  .specimen {
    display: flex;
    align-items: center;
    gap: 16px;
  }

  .spec-art {
    height: min(24vh, 240px);
  }

  .spec-placard {
    margin-top: 0;
  }

  .spec-adds {
    min-height: 40px;
    padding-top: 6px;
    justify-content: flex-start;
  }

  /* The thread drops below the hang's open label-line; it shares no
     column with the corner placard, so it may sit deep in the hem. */
  .invite {
    bottom: max(8vh, 54px);
  }

  .placard {
    line-height: 1.6;
  }
}

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }

  .home,
  .brand,
  .placard,
  .spec-placard,
  .invite,
  .stage.stubbed .stub,
  .stage.marking:not(.stubbed) .atelier > * {
    animation: none;
    transition: none;
  }

  .spec-placard {
    opacity: 1;
    transform: none;
  }

  .specimen.is-chosen .spec-title .stitch {
    animation: none;
    clip-path: inset(-2px 0 -2px 0);
  }

  .spec-art,
  .glow,
  .spec-adds,
  .spec-title .stitch,
  .invite,
  .stage.leaving .atelier,
  .drop,
  .proof,
  .mark-invite .formats,
  .inline-act,
  .inline-act::after,
  .cta-hex,
  .cta-flood,
  .cta-label,
  .cta-patch rect,
  .hexcell .cell polygon,
  .hexcell .glyph,
  .hexthread .swatch,
  .hexthread .ring,
  .tip {
    transition: none;
  }

  .cta-hex:hover .cta-patch rect,
  .hexcell.confirming .glyph,
  .inline-act:hover::after,
  .inline-act.confirming::after,
  .home:hover::after {
    animation: none;
  }
}
