/* Board glyphs as CSS masks. A glyph is painted in currentColor, so it follows the text in light and dark. */
/* Paste the rules you use into a single-file page; nothing here loads a file. */
:root {
  --board-u: 1.3px; /* px per board unit for essay marks: one scale everywhere */
  --g-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8.3 12H15.7M12 3V21' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --g-mark-small: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3.5V20.5' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='5' cy='12' r='4.6' fill='currentColor'/%3E%3Ccircle cx='19' cy='12' r='3.6' fill='none' stroke='currentColor' stroke-width='2'/%3E%3C/svg%3E");
  --g-return: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='6' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Cpath d='M16.3 6H20V17H5.5M9 13.4L5.4 17L9 20.6' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
  --g-out: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 9V20H15' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='9.4' cy='14.6' r='3.4' fill='currentColor'/%3E%3Cpath d='M12.6 11.4L20 4M14.2 4H20V9.8' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
  --g-break: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 8'%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='36' cy='4' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --g-end: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --g-quote: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8'%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='4' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --g-index: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='4' cy='20' r='3.4' fill='currentColor'/%3E%3Cpath d='M10.5 4H23M10.5 12H23M10.5 20H23' fill='none' stroke='currentColor' stroke-width='1.4' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
  --g-link: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M1.5 12H8M16 12H22.5M12 1.5V8M12 16V22.5' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M8 8H16V16H8Z' fill='none' stroke='currentColor' stroke-width='1.5' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
  --g-next: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Cpath d='M9.5 12H21M17.2 8.2L21 12L17.2 15.8' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
  --g-previous: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='20' cy='12' r='3.4' fill='currentColor'/%3E%3Cpath d='M14.5 12H3M6.8 8.2L3 12L6.8 15.8' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
  --g-top: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='20' r='3.4' fill='currentColor'/%3E%3Cpath d='M12 14.5V3M8.2 6.8L12 3L15.8 6.8' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
  --g-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M15.5 7.5V3.5H3.5V15.5H7.5' fill='none' stroke='currentColor' stroke-width='1.5' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M8.5 8.5H20.5V20.5H8.5Z' fill='none' stroke='currentColor' stroke-width='1.5' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='14.5' cy='14.5' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --g-feed: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='4' cy='20' r='3.4' fill='currentColor'/%3E%3Cpath d='M4 12H12V20M4 4H20V20' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3C/svg%3E");
  --m-three-three: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M4 12H31.2M4 20H15.7M24.3 20H31.2M4 28H31.2M12 4V31.2M20 4V15.7M20 24.3V31.2M28 4V31.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M4 4H31.2M4 4V31.2' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='20' cy='20' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-fifth-line: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 24'%3E%3Cpath d='M0.8 4H36M8.3 12H36M0.8 20H7.7M16.3 20H36M4 0.8V7.7M4 16.3V23.2M12 0.8V15.7M20 0.8V23.2M28 0.8V23.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M36 0.8V23.2' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-prisoner: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M0.8 4H7.7M16.3 4H23.2M0.8 20H7.7M16.3 20H23.2M4 0.8V7.7M4 16.3V23.2M20 0.8V7.7M20 16.3V23.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='12' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='20' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='12' cy='20' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='4' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-atari: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M0.8 4H7.7M16.3 4H23.2M16.3 12H23.2M0.8 20H7.7M16.3 20H23.2M4 0.8V7.7M4 16.3V23.2M20 0.8V23.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='12' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='4' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='12' cy='20' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-ladder: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Ccircle cx='4' cy='28' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='28' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='20' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='12' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='20' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='12' cy='36' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='20' cy='28' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='28' cy='20' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='36' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-net: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M0.8 4H15.7M16.3 12H23.2M0.8 20H7.7M16.3 20H23.2M4 0.8V7.7M4 16.3V23.2M12 0.8V7.7M20 8.3V23.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-ko: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 24'%3E%3Cpath d='M17.4 12H22.6M20 9.4V14.6' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='12' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='28' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='20' cy='20' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='12' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-seki: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M8.3 12H15.7M12 4V15.7' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M8.3 4H15.7' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='28' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='20' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='20' cy='20' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='4' cy='28' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='12' cy='28' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-two-eyes: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 24'%3E%3Cpath d='M9.4 12H14.6M12 9.4V14.6M25.4 12H30.6M28 9.4V14.6' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='36' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='36' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='36' cy='20' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-ponnuki: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9.4 12H14.6M12 9.4V14.6' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='12' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-tigers-mouth: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 16'%3E%3Cpath d='M8.3 12H15.7M12 8.3V15.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='12' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='12' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-bamboo-joint: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 24'%3E%3Cpath d='M0.8 12H15.2M4 8.3V15.7M12 8.3V15.7' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-empty-triangle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M9.4 4H14.6M12 1.4V6.6' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='12' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-crosscut: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='4' cy='12' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-wedge: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 35 19'%3E%3Cpath d='M9.5 1.5V5.2M9.5 13.8V17.5M17.5 1.5V5.2M17.5 13.8V17.5M25.5 1.5V5.2M25.5 13.8V17.5' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='17.5' cy='9.5' r='3.4' fill='currentColor'/%3E%3Ccircle cx='9.5' cy='9.5' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='25.5' cy='9.5' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-one-point-jump: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 32'%3E%3Cpath d='M8 12.3V19.7M5.4 16H10.6M8 13.4V18.6' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='8' cy='8' r='3.4' fill='currentColor'/%3E%3Ccircle cx='8' cy='24' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-knights-move: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 16'%3E%3Cpath d='M0.8 4H15.7M8.3 12H23.2M4 0.8V7.7M12 0.8V15.2M20 8.3V15.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='4' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-wall: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M8.3 4H31.2M8.3 12H31.2M8.3 20H31.2M8.3 28H31.2M12 0.8V31.2M20 0.8V31.2M28 0.8V31.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='28' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-crawl: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 24'%3E%3Cpath d='M4 16.3V20M12 16.3V20M20 16.3V20M28 16.3V20' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M0.8 20H31.2' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='4' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='12' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='20' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3Ccircle cx='28' cy='4' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-territory: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M4 12H23.7M4 20H23.7M12 4V23.7M20 4V23.7' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M4 4H23.7M4 4V23.7' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='28' cy='4' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='20' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='28' r='3.4' fill='currentColor'/%3E%3Ccircle cx='20' cy='28' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='28' r='3.4' fill='currentColor'/%3E%3Ccircle cx='4' cy='28' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-liberties: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 12H7.7M16.3 12H20M12 4V7.7M12 16.3V20' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='12' cy='4' r='1.7' fill='currentColor'/%3E%3Ccircle cx='4' cy='12' r='1.7' fill='currentColor'/%3E%3Ccircle cx='20' cy='12' r='1.7' fill='currentColor'/%3E%3Ccircle cx='12' cy='20' r='1.7' fill='currentColor'/%3E%3Ccircle cx='12' cy='12' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-handicap: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M4 12H7.7M16.3 12H23.7M32.3 12H36M4 20H36M4 28H7.7M16.3 28H23.7M32.3 28H36M12 4V7.7M12 16.3V23.7M12 32.3V36M20 4V36M28 4V7.7M28 16.3V23.7M28 32.3V36' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M4 4H36M4 36H36M4 4V36M36 4V36' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='12' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='12' r='3.4' fill='currentColor'/%3E%3Ccircle cx='12' cy='28' r='3.4' fill='currentColor'/%3E%3Ccircle cx='28' cy='28' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-tengen: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M0.8 4H39.2M0.8 12H39.2M0.8 20H15.7M24.3 20H39.2M0.8 28H39.2M0.8 36H39.2M4 0.8V39.2M12 0.8V39.2M20 0.8V15.7M20 24.3V39.2M28 0.8V39.2M36 0.8V39.2' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='20' cy='20' r='3.4' fill='currentColor'/%3E%3C/svg%3E");
  --m-speaks-back: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M0 8H11.7M20.3 8H24M0 16H3.7M12.3 16H24M8 0V11.7M8 20.3V24M16 0V3.7M16 12.3V24' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='8' cy='16' r='3.4' fill='currentColor'/%3E%3Ccircle cx='16' cy='8' r='2.75' fill='none' stroke='currentColor' stroke-width='1.3'/%3E%3C/svg%3E");
  --m-world: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M4 12H36M4 20H36M4 28H36M12 4V36M20 4V36M28 4V36' fill='none' stroke='currentColor' stroke-width='1' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Cpath d='M4 4H36M4 36H36M4 4V36M36 4V36' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='butt' stroke-linejoin='miter'/%3E%3Ccircle cx='20' cy='20' r='1.7' fill='currentColor'/%3E%3C/svg%3E");
}
.g, .m { display: inline-block; flex-shrink: 0; background: currentColor;
  -webkit-mask: var(--glyph) center / contain no-repeat; mask: var(--glyph) center / contain no-repeat; }
.g { width: 1em; height: 1em; vertical-align: -0.17em; }
.m { width: calc(var(--w) * var(--board-u)); height: calc(var(--h) * var(--board-u)); }

/* working glyphs, with the sizes they take in running text */
.g-mark { --glyph: var(--g-mark); width: 1.35em; height: 1.35em; vertical-align: -0.34em; }
.g-mark-small { --glyph: var(--g-mark-small); width: 1.35em; height: 1.35em; vertical-align: -0.34em; }
.g-return { --glyph: var(--g-return); width: 0.98em; height: 0.98em; vertical-align: -0.2em; margin-left: 0.3em; }
.g-out { --glyph: var(--g-out); width: 0.86em; height: 0.86em; vertical-align: -0.08em; margin: 0 0.1em 0 0.22em; }
.g-break { --glyph: var(--g-break); display: block; width: 60px; height: 12px; margin: 2.75rem auto 2.5rem; }
.g-end { --glyph: var(--g-end); width: 0.62em; height: 0.62em; vertical-align: 0.01em; margin-left: 0.4em; }
.g-quote { --glyph: var(--g-quote); width: 0.8em; height: 0.4em; vertical-align: 0.42em; }
.g-index { --glyph: var(--g-index); }
.g-link { --glyph: var(--g-link); }
.g-next { --glyph: var(--g-next); }
.g-previous { --glyph: var(--g-previous); }
.g-top { --glyph: var(--g-top); }
.g-copy { --glyph: var(--g-copy); }
.g-feed { --glyph: var(--g-feed); }

/* essay marks: --w and --h are the mark's size in board units */
.m-three-three { --glyph: var(--m-three-three); --w: 32; --h: 32; }
.m-fifth-line { --glyph: var(--m-fifth-line); --w: 40; --h: 24; }
.m-prisoner { --glyph: var(--m-prisoner); --w: 24; --h: 24; }
.m-atari { --glyph: var(--m-atari); --w: 24; --h: 24; }
.m-ladder { --glyph: var(--m-ladder); --w: 40; --h: 40; }
.m-net { --glyph: var(--m-net); --w: 24; --h: 24; }
.m-ko { --glyph: var(--m-ko); --w: 32; --h: 24; }
.m-seki { --glyph: var(--m-seki); --w: 32; --h: 32; }
.m-two-eyes { --glyph: var(--m-two-eyes); --w: 40; --h: 24; }
.m-ponnuki { --glyph: var(--m-ponnuki); --w: 24; --h: 24; }
.m-tigers-mouth { --glyph: var(--m-tigers-mouth); --w: 24; --h: 16; }
.m-bamboo-joint { --glyph: var(--m-bamboo-joint); --w: 16; --h: 24; }
.m-empty-triangle { --glyph: var(--m-empty-triangle); --w: 16; --h: 16; }
.m-crosscut { --glyph: var(--m-crosscut); --w: 16; --h: 16; }
.m-wedge { --glyph: var(--m-wedge); --w: 35; --h: 19; }
.m-one-point-jump { --glyph: var(--m-one-point-jump); --w: 16; --h: 32; }
.m-knights-move { --glyph: var(--m-knights-move); --w: 24; --h: 16; }
.m-wall { --glyph: var(--m-wall); --w: 32; --h: 32; }
.m-crawl { --glyph: var(--m-crawl); --w: 32; --h: 24; }
.m-territory { --glyph: var(--m-territory); --w: 32; --h: 32; }
.m-liberties { --glyph: var(--m-liberties); --w: 24; --h: 24; }
.m-handicap { --glyph: var(--m-handicap); --w: 40; --h: 40; }
.m-tengen { --glyph: var(--m-tengen); --w: 40; --h: 40; }
.m-speaks-back { --glyph: var(--m-speaks-back); --w: 24; --h: 24; }
.m-world { --glyph: var(--m-world); --w: 40; --h: 40; }

/* ==========================================================================
   Slow Fast — essay reading surface
   --------------------------------------------------------------------------
   Ported from the visual reference at
   .config/slowfast-workspace/essay-reference.html (style block, lines 11-173).

   Rules marked LIFTED are byte-for-byte the reference's intent and must not
   drift. Rules marked NORMALISED and INVENTED are deliberate departures and
   are each recorded in docs/design/essay-reading-surface.md so the fidelity
   gate can exempt them.

   No JavaScript is served with this stylesheet. There is no theme toggle.
   Font delivery is SELF-HOSTED, and this file is the only place it is
   declared. The page shell emits no third-party font link and no preconnect,
   so an essay page reaches exactly one origin and no reader is disclosed to a
   font CDN in order to see type. See section 0.
   ========================================================================== */


/* --------------------------------------------------------------------------
   0. FONTS
   Newsreader, self-hosted, OFL-1.1. Two files and no more: it is a variable
   font, so one roman binary carries every weight and optical size the site
   asks for and one italic binary carries the same. Static instances would be
   a dozen files to say less.

   `font-weight: 400 500` is the range this surface actually uses — body text
   at 400, `h2` and `strong` at 500 — declared as a range so the browser
   interpolates rather than synthesising. The binaries carry the wider 200-800
   axis upstream ships; declaring the narrower range here is what keeps a
   stray `font-weight: 700` from rendering as something this design never
   chose. The `opsz` 6-72 axis is what `body { font-optical-sizing: auto }`
   drives, and it is the reason the same outlines hold up at the 3rem h1 and
   at the .86rem notes.

   `font-display: swap` is deliberate and matches the motion budget: the
   fallback stack paints immediately and the webfont swaps in when it lands.
   Nothing on this surface is allowed to withhold legible text.

   Provenance, pinned upstream refs and the reason the axis was NOT narrowed
   are in `fonts/PROVENANCE.md`. The licence travels with the binaries: the
   build copies `fonts/OFL.txt` into `dist/essays/assets/fonts/`.
   INVENTED — the reference linked Google Fonts; this surface does not.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("/assets/fonts/newsreader-variable-roman.woff2") format("woff2");
}

@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url("/assets/fonts/newsreader-variable-italic.woff2") format("woff2");
}


/* --------------------------------------------------------------------------
   1. TOKENS
   Three blocks, in this exact order: bare :root, the prefers-color-scheme
   query guarded by :root:not([data-theme="light"]), then :root[data-theme="dark"].
   All six tokens are redefined in full in each of the two dark blocks so that
   no colour has its only definition inside a media query.
   LIFTED.
   -------------------------------------------------------------------------- */

:root {
  --paper: #fcfcfa;
  --ink: #1b1d24;
  --ink-2: #6a6d78;
  --rule: #dcdcd6;
  --evidence: #2a58b4;
  --plate: #eeeeea;
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #121316;
    --ink: #e6e4de;
    --ink-2: #9295a0;
    --rule: #2c2e35;
    --evidence: #88a9ec;
    --plate: #1d1f25;
  }
}

/* INTENTIONALLY DORMANT HOOK.
   Nothing in this slice sets data-theme. There is no toggle, no client
   JavaScript, and no server-side preference. The attribute selectors are kept
   so that an explicit per-viewer choice can be wired up later without
   restructuring the cascade: the light guard above lets a future
   data-theme="light" win over an OS dark preference, and the block below lets
   a future data-theme="dark" win over an OS light preference. Until such a
   control exists these two selectors match nothing, by design. */
:root[data-theme="dark"] {
  --paper: #121316;
  --ink: #e6e4de;
  --ink-2: #9295a0;
  --rule: #2c2e35;
  --evidence: #88a9ec;
  --plate: #1d1f25;
}


/* --------------------------------------------------------------------------
   2. RESET AND BODY
   LIFTED.
   -------------------------------------------------------------------------- */

html {
  -webkit-text-size-adjust: 100%;
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: "Newsreader", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-optical-sizing: auto;
  font-size: 1.0625rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern", "liga";
}

@media (min-width: 40em) {
  body {
    font-size: 1.1875rem;
    line-height: 1.5;
  }
}

i,
em {
  font-style: italic;
}

b,
strong {
  font-weight: 500;
}


/* --------------------------------------------------------------------------
   3. LAYOUT
   The measure is 38rem on essay pages and on the index alike — one measure is
   what makes them read as one publication rather than a feed bolted to a
   magazine.

   --gutter mirrors the horizontal half of .page's padding so the wide-figure
   breakout in section 9 and the page padding can never fall out of agreement:
   change one number here and both follow.

   overflow-x: clip contains the wide-figure breakout. clip is used rather than
   hidden precisely because it does not create a scroll container, so
   scroll-behavior and :target scrolling into the notes still work.
   .page padding and max-width are LIFTED; --gutter and overflow-x are INVENTED.
   -------------------------------------------------------------------------- */

.page {
  --gutter: 1.25rem;
  max-width: 33rem;
  margin: 0 auto;
  padding: 3.5rem 1.25rem 6rem;
  overflow-x: clip;
}

@media (min-width: 40em) {
  .page {
    --gutter: 3.25rem;
    padding: 6.5rem 3.25rem 7rem;
  }
}


/* --------------------------------------------------------------------------
   4. MASTHEAD
   INVENTED — the reference has no masthead at all.
   Sits outside <header> as the first child of .page. Carries its own
   text-indent: 0 rather than relying on the "header p" exception, because it
   is not inside header and may contain a paragraph.
   On an essay page it carries the bare "Slow Fast" wordmark. On the index it
   also carries the stance line beneath that wordmark.
   -------------------------------------------------------------------------- */

.masthead {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: .86rem;
  letter-spacing: .02em;
  color: var(--ink-2);
  text-indent: 0;
  margin: 0 0 3.2rem;
}

.masthead a {
  color: inherit;
  text-decoration: none;
}

.masthead .wordmark {
  color: var(--ink);
}

/* The stance line is content, not chrome, and renders on the index only. */
.masthead .stance {
  display: block;
  margin: .55rem 0 0;
  color: var(--ink-2);
  text-indent: 0;
  font-style: italic;
}

/* THE MASTHEAD'S RIGHT-HAND SIDE.
   `.masthead` is space-between and was always built for two items. Without a
   second one the about page is published and unreachable from every reading
   page. It inherits the masthead's own quiet scale — this is a way out, not a
   thing to look at. */
.masthead-about {
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
}

@media (prefers-reduced-motion: no-preference) {
  .masthead-about {
    transition: color 120ms ease;
  }
}

.masthead-about:hover,
.masthead-about:focus-visible {
  color: var(--ink);
}

/* THE SITE FOOTER. Index only. The standalone pages would otherwise be
   reachable from the about page and from each other, but never from the front
   door. Same quiet scale as the masthead; the rule above it does the
   separating, exactly as `.notes` does on an essay. */
.site-footer {
  margin-top: 4.5rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem;
  font-size: .86rem;
  letter-spacing: .02em;
  color: var(--ink-2);
  text-indent: 0;
}

.site-footer a {
  color: inherit;
  text-decoration: none;
}

@media (prefers-reduced-motion: no-preference) {
  .site-footer a {
    transition: color 120ms ease;
  }
}

.site-footer a:hover,
.site-footer a:focus-visible {
  color: var(--ink);
}


/* On the index the publication's name is the page's heading, so it is an
   <h1>. It must not inherit the essay-title type scale — visually it stays
   exactly the masthead wordmark it was before. */
.masthead h1.wordmark-heading {
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  margin: 0;
}


/* --------------------------------------------------------------------------
   5. HEADER, TITLE AND BYLINE
   NORMALISED: the reference's single fluid h1 size becomes three fixed
   breakpoint sizes, and its negative tracking is dropped altogether rather
   than written out as a zero value.
   Everything else LIFTED.
   -------------------------------------------------------------------------- */

header h1 {
  font-weight: 400;
  font-size: 2.05rem;
  line-height: 1.06;
  margin: 0 0 1.4rem;
  text-wrap: pretty;
}

@media (min-width: 40em) {
  header h1 {
    font-size: 2.5rem;
  }
}

@media (min-width: 52em) {
  header h1 {
    font-size: 3rem;
  }
}

header .byline {
  font-style: italic;
  font-size: 1.0625rem;
  color: var(--ink-2);
  margin: 0 0 4.25rem;
}

/* The <time> element is emitted inside the fused byline string so the byline
   renders pixel-identically while becoming machine-readable. */
header .byline time {
  font-style: inherit;
  color: inherit;
}

/* INVENTED. A header image sits below the title and byline. The generator adds
   this class to <header> rather than relying on :has(), and it pulls the
   byline's generous 4.25rem trailing space in to 1.6rem so the image reads as
   part of the opening rather than as the first thing in the prose. */
header.has-header-image .byline {
  margin-bottom: 1.6rem;
}


/* --------------------------------------------------------------------------
   6. PROSE
   NORMALISED — this is the one substantive departure from the reference's
   setting of the page.

   The reference sets prose the way a book does: p { margin: 0 } with a 1.55em
   first-line indent, so paragraphs are separated by the indent alone and the
   column runs as an unbroken block of type. That works on a printed page and
   it works for the reference essay, which is broken up by seven numbered
   sections. It does not hold for an essay with no sections at all — several
   here have none — where it renders as one undifferentiated wall.

   So: space between paragraphs, and NO first-line indent. The two are
   alternatives, not additions; using both is a redundancy that reads as an
   error. Indentation is still never stored in the content model — a paragraph
   is <p> and nothing more — the rule set simply separates them differently.

   1.15em is a little under one line (line-height is 1.58), which separates
   clearly without letting the column drift apart.
   -------------------------------------------------------------------------- */

p {
  margin: 0 0 1.15em;
  hyphens: auto;
  /* Never hyphenate a word shorter than 6 characters, and never leave fewer
     than 3 before or after the break. Unconstrained `hyphens: auto` on a
     ragged-right column breaks two-syllable words and litters the right edge
     with hyphens that buy nothing. */
  hyphenate-limit-chars: 6 3 3;
  /* Costs the last lines so a paragraph does not end on a single short word.
     The reference applies this to display type only; body text is where a
     runt is actually distracting. */
  text-wrap: pretty;
}

p:last-child {
  margin-bottom: 0;
}

p.close {
  margin-top: 1.55em;
}

h2 {
  font-weight: 500;
  font-size: 1.42rem;
  line-height: 1.22;
  margin: 3.6rem 0 1.15rem;
  text-wrap: pretty;
  /* Every numbered heading carries an id, so it is a deep-link target. Without
     this it lands flush against the top of the viewport with no air above it.
     The notes list already does the same. */
  scroll-margin-top: 1.5rem;
}

/* The section number. Ordinals are computed at render from document order and
   never stored. */
h2 .n {
  font-weight: 400;
  color: var(--ink-2);
  margin-right: .55em;
}

/* INVENTED. Prose links get the same treatment as note links so that a link
   mark in a body paragraph never falls back to the browser default. Neither
   essay in this slice contains one, so this rule changes nothing today. */
article a {
  color: var(--evidence);
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: .14em;
}

/* Footnote references. LIFTED. */
sup.ref {
  font-size: .6em;
  line-height: 0;
  vertical-align: .62em;
  margin-left: .06em;
}

sup.ref a {
  color: var(--evidence);
  text-decoration: none;
  padding: 0 .12em;
}

sup.ref a:hover {
  text-decoration: underline;
}

/* LIFTED. */
a:focus-visible {
  outline: 2px solid var(--evidence);
  outline-offset: 2px;
  border-radius: 2px;
}


/* --------------------------------------------------------------------------
   7. PULL QUOTES
   LIFTED. Note that .pull declares NO font-weight — it inherits the body's,
   and that is the reference's intent, not an omission. Its negative tracking
   is dropped per the same normalisation as the h1.
   Whether a pull quote carries aria-hidden is computed at render from whether
   its text already occurs in the prose; it is never a styling concern.
   -------------------------------------------------------------------------- */

.pull {
  margin: 2.4rem 0;
  padding: 0 1.5rem 0 0;
  font-size: 1.42rem;
  line-height: 1.28;
  text-indent: 0;
  text-wrap: pretty;
}


/* --------------------------------------------------------------------------
   8. SECTION BREAKS
   INVENTED — the reference has no section breaks. An EMPTY element carrying
   role="separator", which is what announces the break.
   It used to carry the author's literal em dash as text. It now carries the
   `break` glyph — black, white, black — and the box that paints it is in
   section 15 with the rest of the glyphs. What is left here is what the
   element is regardless of what is drawn on it.
   -------------------------------------------------------------------------- */

p.brk {
  text-indent: 0;
  text-align: center;
  color: var(--ink-2);
}


/* --------------------------------------------------------------------------
   9. FIGURES
   INVENTED — the reference has no figures.

   layout: "column" is the 38rem measure and needs no breakout.
   layout: "wide" breaks out WITHOUT shifting the box. The usual half-width
   translate trick is deliberately not used: it would create a stacking
   context, risks fractional-pixel blur on the image, and interferes with
   :target scrolling. Instead a negative margin-inline pulls the figure out to
   half of the wider measure, bounded by the viewport minus one gutter, so it
   never touches the screen edge and never overflows .page's clip.

   A figure whose status is "pending" carries no <img> at all — it renders as a
   caption alone, not as an empty frame.
   -------------------------------------------------------------------------- */

figure {
  margin: 2.8rem 0;
}

figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 2px;
}

figure figcaption {
  font-size: .86rem;
  line-height: 1.5;
  color: var(--ink-2);
  text-indent: 0;
  margin-top: .7rem;
}

figure figcaption .credit {
  display: block;
  margin-top: .3rem;
}

figure.wide {
  margin-inline: calc(50% - min(26rem, 50vw - var(--gutter)));
}

/* The header image, below title and byline. */
figure.header {
  margin: 0 0 3.4rem;
}


/* --------------------------------------------------------------------------
   10. NOTES
   The notes section lives inside <main> but outside </article>.
   LIFTED in full, including the plate bleed on :target — the box-shadow spreads
   the plate .55rem past the list item's own box so a targeted note reads as a
   physical plate laid on the paper rather than as a highlighted rectangle.
   -------------------------------------------------------------------------- */

.notes {
  margin-top: 5.5rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--rule);
  font-size: .86rem;
  line-height: 1.5;
}

@media (min-width: 40em) {
  .notes {
    font-size: .92rem;
  }
}

.notes h2 {
  font-size: 1rem;
  font-weight: 500;
  margin: 0 0 1.1rem;
}

.notes ol {
  list-style: none;
  margin: 0;
  padding: 0;
}

.notes li {
  position: relative;
  padding-left: 2.1rem;
  margin: 0 0 .8rem;
  scroll-margin-top: 1.5rem;
}

.notes li .back {
  position: absolute;
  left: 0;
  top: 0;
  width: 1.7rem;
  color: var(--evidence);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

/* THE PLATE BLEED. */
.notes li:target {
  background: var(--plate);
  box-shadow: 0 0 0 .55rem var(--plate);
  border-radius: 2px;
}

.notes a {
  color: var(--evidence);
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: .14em;
}

.notes .back:hover {
  text-decoration: underline;
}


/* --------------------------------------------------------------------------
   11. ESSAY NAV
   INVENTED. Previous / All essays / next, at the foot of an essay page,
   inside <main> and after the notes. Hidden in print.
   -------------------------------------------------------------------------- */

nav.essay-nav {
  margin-top: 4.5rem;
  padding-top: 1.6rem;
  border-top: 1px solid var(--rule);
  display: flex;
  justify-content: space-between;
  gap: 1.2rem;
  font-size: .92rem;
  color: var(--ink-2);
}

nav.essay-nav a {
  color: var(--ink-2);
  text-decoration: none;
}

nav.essay-nav a:hover {
  text-decoration: underline;
}

/* Stands in for an absent neighbour so "All essays" keeps its place.
   It must NOT grow: `justify-content: space-between` is what does the
   positioning, and a growing spacer would absorb the free space and leave
   nothing to distribute, packing the two real links together. */
nav.essay-nav .spacer {
  flex: 0 0 auto;
}


/* --------------------------------------------------------------------------
   12. INDEX PAGE
   INVENTED. Same 38rem measure as an essay page. Items are 2.8rem apart with
   no rules between them — the space does the separating.
   -------------------------------------------------------------------------- */

.essay-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.essay-list li {
  margin: 0 0 2.8rem;
}

.essay-list li:last-child {
  margin-bottom: 0;
}

.essay-list .title {
  font-size: 1.42rem;
  font-weight: 500;
  line-height: 1.22;
  margin: 0;
  text-wrap: pretty;
}

.essay-list .title a {
  color: var(--ink);
  text-decoration: none;
}

.essay-list .date {
  display: block;
  font-size: .86rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  margin-top: .45rem;
}

.essay-list .excerpt {
  font-size: 1.0625rem;
  line-height: 1.5;
  color: var(--ink-2);
  text-indent: 0;
  margin-top: .55rem;
}

/* The most recent essay is featured with a larger title, echoing the first two
   h1 breakpoints so the index and an essay page share one type scale. */
.essay-list li.featured {
  margin-bottom: 3.6rem;
}

.essay-list li.featured .title {
  font-size: 2.05rem;
  font-weight: 400;
  line-height: 1.1;
}

@media (min-width: 40em) {
  .essay-list li.featured .title {
    font-size: 2.5rem;
  }
}


/* --------------------------------------------------------------------------
   13. SKIP LINK
   INVENTED. Visually hidden until focused, then pinned top-left on the plate.
   Clipped rather than display:none so it stays in the focus order.
   -------------------------------------------------------------------------- */

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

.skip-link:focus,
.skip-link:focus-visible {
  position: fixed;
  top: .75rem;
  left: .75rem;
  z-index: 10;
  width: auto;
  height: auto;
  margin: 0;
  padding: .55rem .9rem;
  overflow: visible;
  clip-path: none;
  background: var(--plate);
  color: var(--ink);
  border-radius: 2px;
  font-size: .92rem;
  text-decoration: none;
}


/* --------------------------------------------------------------------------
   14. MOTION
   The motion budget is one transition and the reference's already-gated
   scroll-behavior. There is deliberately NO entrance fade anywhere: it would
   delay first legible text, which is the one thing this surface exists to
   deliver. No keyframes are declared in this file.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .essay-list a {
    transition: color 120ms ease, opacity 120ms ease;
  }
}

.essay-list a:hover,
.essay-list a:focus-visible {
  color: var(--evidence);
}


/* --------------------------------------------------------------------------
   15. GLYPHS
   INVENTED — the reference has none.

   The glyphs are a set drawn for this site in the notation of a Go record:
   three primitives, one scale, everything in `currentColor`. They arrive as
   custom properties from `src/assets/glyphs/board.css`, which is GENERATED by
   `glyphs/source/board.py` and concatenated ahead of this file into the one
   hashed stylesheet. Nothing in this section may hand-edit that file; a
   regeneration would silently revert it.

   EVERY GLYPH HERE IS A MASK OVER currentColor. That is the whole reason this
   approach was taken over an <img> or an inline <svg>: a mask cuts the drawing
   out of the text's own colour, so a glyph is never a colour of its own and
   follows light and dark with no second definition and no second asset. The
   SVG travels inside the stylesheet as a `data:` URI, so no glyph costs a
   request and none of them reaches a second origin.

   THE WORKING GLYPHS ARE PSEUDO-ELEMENTS, so no essay's markup changed to get
   one. The essay MARK is real markup — `<span class="m m-tengen">` — because
   it is a per-document choice and content has to be able to name it.

   DECORATIVE, THEREFORE SILENT. Not one glyph here is announced: a
   pseudo-element is not in the accessibility tree, and the marks carry
   aria-hidden. Every one of them repeats something the page already says in
   words. The pack's rule is that a glyph which IS the content of a control
   needs words of its own; no such glyph is used on this site.

   SIX OF THE PACK'S FOURTEEN WORKING GLYPHS ARE DELIBERATELY UNUSED: `mark`
   (the large site mark — there is no page big enough for it), `return` (the
   note's own numeral already goes back), `link` (no per-heading anchor is
   offered), `copy`, `top` and `feed` (no visible feed link exists; the index
   advertises the feed in the head only). They stay drawn and available.
   -------------------------------------------------------------------------- */

/* The scale for the essay marks: pixels per board unit. `board.css` declares
   it too; this is the site's value, and it wins because this file is
   concatenated after the generated one. 1.3px makes the widest mark — 40
   units — 52px. A mark is NEVER scaled on its own: set the scale once and let
   the marks differ in size, the way diagrams do in a Go book. */
:root {
  --board-u: 1.3px;
}

/* The shared plumbing. A box, filled with the text's colour, with the drawing
   cut out of it. `mask` is still prefixed for WebKit, and both properties are
   declared in full rather than via the shorthand so that a browser with only
   the prefixed form gets every part of it. */
.masthead .wordmark::before,
p.close::after,
.pull::before,
.notes a[href^="http"]::after,
nav.essay-nav a[rel="prev"]::before,
nav.essay-nav a[href="/"]::before,
nav.essay-nav a[rel="next"]::after {
  content: "";
  display: inline-block;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-size: contain;
          mask-size: contain;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* THE SITE MARK, beside the wordmark on every page: black, white, and the
   empty point between them, cut bolder for small sizes. */
.masthead .wordmark::before {
  -webkit-mask-image: var(--g-mark-small);
          mask-image: var(--g-mark-small);
  width: 1.35em;
  height: 1.35em;
  margin-right: .45em;
  vertical-align: -.34em;
}

/* THE END MARK: one stone, played after the last line of the essay. */
p.close::after {
  -webkit-mask-image: var(--g-end);
          mask-image: var(--g-end);
  width: .62em;
  height: .62em;
  margin-left: .4em;
  vertical-align: .01em;
}

/* A STONE PLAYED OFF THE CORNER OF THE BOARD, after a source that leaves the
   site. The attribute selector is the whole rule: a note's own numeral links
   to `#r7` and a cross-reference to another essay links to `/essays/…`, so
   neither takes the mark, and no renderer has to know which is which. */
.notes a[href^="http"]::after {
  -webkit-mask-image: var(--g-out);
          mask-image: var(--g-out);
  width: .86em;
  height: .86em;
  margin: 0 .1em 0 .22em;
  vertical-align: -.08em;
}

/* TWO STONES AT CAP HEIGHT, where a quotation mark would be.
   Inline on a narrow screen and hung in the margin on a wide one. The switch
   is not taste: .page's gutter is 1.25rem on a narrow screen and the glyph
   hangs 1.35em of a 1.42rem line — about 31px — so hanging it there would put
   it under `overflow-x: clip` and cut it in half. */
.pull {
  position: relative;
  padding-left: 1.35em;
}

.pull::before {
  -webkit-mask-image: var(--g-quote);
          mask-image: var(--g-quote);
  position: absolute;
  left: 0;
  top: .36em;
  width: .8em;
  height: .4em;
}

@media (min-width: 40em) {
  .pull {
    padding-left: 0;
  }

  .pull::before {
    left: -1.35em;
  }
}

/* THE SECTION BREAK: black, white, black. A block, centred, sized in pixels
   rather than ems because it belongs to the page and not to a line of type. */
p.brk {
  display: block;
  width: 60px;
  height: 12px;
  margin: 2.75rem auto 2.5rem;
  background: currentColor;
  -webkit-mask: var(--g-break) center / contain no-repeat;
          mask: var(--g-break) center / contain no-repeat;
}

/* PREVIOUS / ALL ESSAYS / NEXT: a stone where you are and an arrow where you
   go, and for the index, the record of moves as a list with stones for
   bullets. The arrows point outward from the centre link, so the row reads
   left to right the way the essays do. */
nav.essay-nav a[rel="prev"]::before {
  -webkit-mask-image: var(--g-previous);
          mask-image: var(--g-previous);
  width: 1em;
  height: 1em;
  margin-right: .4em;
  vertical-align: -.17em;
}

nav.essay-nav a[href="/"]::before {
  -webkit-mask-image: var(--g-index);
          mask-image: var(--g-index);
  width: 1em;
  height: 1em;
  margin-right: .4em;
  vertical-align: -.17em;
}

nav.essay-nav a[rel="next"]::after {
  -webkit-mask-image: var(--g-next);
          mask-image: var(--g-next);
  width: 1em;
  height: 1em;
  margin-left: .4em;
  vertical-align: -.17em;
}

/* THE ESSAY MARK. `board.css` gives `.m` its mask and its box — the box comes
   from the mark's own size in board units and the scale above — so all that is
   left here is where it sits and how loud it is. --ink-2, because it is a
   signature and not a heading.

   Under the byline on an essay page; above the title on the index, where the
   column then reads as a page of diagrams. */
header .m {
  display: block;
  margin: 1.5rem 0 0;
  color: var(--ink-2);
}

.essay-list .m {
  display: block;
  margin: 0 0 .9rem;
  color: var(--ink-2);
}


/* --------------------------------------------------------------------------
   16. PRINT
   LIFTED, extended to drop the three invented navigational elements — they
   are all screen affordances and carry no meaning on paper.
   -------------------------------------------------------------------------- */

@media print {
  body {
    background: #fff;
    color: #000;
    font-size: 11pt;
  }

  .page {
    max-width: none;
    padding: 0;
  }

  sup.ref a,
  .notes a,
  .notes .back,
  article a {
    color: #000;
  }

  .notes li:target {
    background: none;
    box-shadow: none;
  }

  .masthead,
  nav.essay-nav,
  .skip-link {
    display: none;
  }

  figure.wide {
    margin-inline: 0;
  }

  /* THE GLYPHS DO NOT PRINT. Every one of them is a mask over a background,
     and a background is the first thing a print engine drops — the box would
     survive and the drawing would not. So they are removed outright, and the
     one glyph that carried meaning rather than ornament gets its character
     back: the section break returns to an em dash on paper. */
  p.close::after,
  .pull::before,
  .notes a[href^="http"]::after,
  header .m,
  .essay-list .m {
    display: none;
  }

  p.brk {
    display: block;
    width: auto;
    height: auto;
    margin: 2.6rem 0;
    background: none;
    -webkit-mask: none;
            mask: none;
  }

  p.brk::before {
    content: "—";
  }
}
