/* ===========================================================================
   Site stylesheet.

   This loads after the theme stylesheet and wins on conflict. It carries the
   2026 redesign: design tokens, a dark mode, fluid type, and one variable
   typeface.

   Sections
     1. Tokens
     2. Typeface
     3. Reset and base
     4. Layout
     5. Headings and prose
     6. Links, code, quotes, tables
     7. Tufte margin notes and side notes
     8. Header, navigation, footer
     9. Post lists
    10. Theme toggle
    11. Gallery and lightbox
    12. Accessibility and print
   =========================================================================== */


/* --- 1. Tokens ----------------------------------------------------------- */

:root {
  /* Palette: 日本の伝統色, traditional Japanese colors.

     The accents are the canonical colours at their published values. The light
     grounds are mixed toward 月白 and 銀鼠 rather than taken from them, because
     the true values are too blue and too dark for a page. A token that is a
     mix says "toward". */

  --bg:        #f7f9fb;  /* toward 月白  geppaku      — moon white, a cool cast */
  --surface:   #eff2f6;  /* a step down from the ground */
  --surface-2: #e4e9ef;  /* panels and code wells */
  --fg:        #1a1c1e;  /* 墨        sumi         — ink, cooled a shade */
  --fg-strong: #0b0d0f;  /* 呂色      ro-iro       — polished black lacquer */
  --muted:     #646b74;  /* toward 銀鼠  ginnezumi    — silver grey */
  --rule:      #d9dfe6;  /* hairlines, same cool family */
  --accent:    #19448e;  /* 瑠璃紺    rurikon      — lapis navy */
  --accent-2:  #9e3d3f;  /* 蘇芳      suou         — sappanwood red */
  --shadow:    rgba(20, 26, 34, 0.10);

  --measure: 78ch;       /* The programming column, not the prose column. */
  --pad: clamp(1rem, 4vw, 2.5rem);  /* One inset. The header, the content and
                                       the underline all use it, so they share
                                       a left edge. */
  --stub-square: clamp(4.5rem, 7vw, 6.5rem);  /* Thumbnail side. Both axes. */
  --margin-col: 15rem;
  --gap: clamp(1.2rem, 3vw, 2.6rem);

  --step--1: clamp(0.78rem, 0.74rem + 0.18vw, 0.87rem);
  --step-0:  clamp(0.98rem, 0.93rem + 0.24vw, 1.09rem);
  --step-1:  clamp(1.18rem, 1.08rem + 0.45vw, 1.42rem);
  --step-2:  clamp(1.45rem, 1.26rem + 0.85vw, 2.00rem);
  --step-3:  clamp(1.80rem, 1.45rem + 1.55vw, 2.80rem);

  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;
}

[data-theme="dark"] {
  /* Indigo carries the dark mode, as the ground rather than the accent. Text
     is warm off-white, never pure white. */

  --bg:        #0f2350;  /* 濃藍      koiai        — deep indigo */
  --surface:   #17305f;  /* 紺青      konjou       — navy blue */
  --surface-2: #1f3c6e;  /* 藍色      ai-iro       — indigo */
  --fg:        #ede4cd;  /* 練色      neri-iro     — glossed silk, not white */
  --fg-strong: #fbfaf5;  /* 生成り色  kinari-iro   — unbleached cloth */
  --muted:     #b3ada0;  /* 利休白茶  rikyushiracha — pale grey-brown */
  --rule:      #26406f;  /* 御召茶に近い藍 — a lifted indigo for hairlines */
  --accent:    #83ccd2;  /* 白群      byakugun     — pale mineral blue */
  --accent-2:  #f5b199;  /* 一斤染    ikkonzome    — light safflower */
  --shadow:    rgba(0, 0, 0, 0.55);
}

/* --- 2. Typeface --------------------------------------------------------- */

/* Plex Mono ships at 400 and 600 only. Do not request another weight for a
   mono element, or the browser draws a synthetic bold. Plex Sans is variable
   across 300-700, so paragraphs may use any weight in that range. */

/* IBM Plex Mono sets the structure. IBM Plex Sans sets the paragraphs, because
   uniform advance widths slow reading at length. The two are one superfamily,
   drawn together, so the pairing holds. */

.u-mono,
h1, h2, h3, h4, h5, h6,
nav, code, pre, kbd, samp,
figcaption, caption, th,
.post-meta, .content-meta, .sidenote, .marginnote,
.gallery-caption, .lightbox-panel h3,
table, time, .theme-toggle {
  font-family: var(--font-mono);
}

/* Navigation and footer meta are structure, so they take the mono face.
   These need `nav li` rather than `nav`, because `li` sits in the prose list
   below and a direct match beats an inherited one. */
nav li, nav a,
.page-footer, .page-footer a, .page-footer li,
.stub-meta, .stubs-heading {
  font-family: var(--font-mono);
}

body, p, li, dd, dt, blockquote, .lightbox-panel p,
.sans {
  font-family: var(--font-sans);
}

/* Form controls do not inherit a font. Without this they fall back to the
   system UI face, which is neither of ours. */
button, input, select, textarea {
  font-family: inherit;
  font-size: inherit;
}

/* Theme classes that carry their own face. None is used today, so these are
   latent leaks: the moment a page uses one, it would bring in et-book or Gill
   Sans. See tufte.scss and hugo-tufte-options.scss. */
.numeral, .code {
  font-family: var(--font-mono);
}
div.table-wrapper {
  font-family: inherit;
}


/* --- 3. Reset and base --------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  /* The theme hardcodes 15px, which overrides the reader's own setting. */
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  background-color: var(--bg);
  color: var(--fg);
  font-size: var(--step-0);
  line-height: 1.65;
  max-width: none;
  margin: 0;
  padding: 0;
  width: auto;
  counter-reset: sidenote-counter;
  -webkit-font-smoothing: antialiased;
  transition: background-color 0.18s ease, color 0.18s ease;
}


/* --- 4. Layout ----------------------------------------------------------- */

/* Undo the theme's wrappers only. This must NOT name `article` or `header`:
   `body > article` outranks the `article` rule below, and it silently removed
   the max-width that keeps the body aligned with the header. */
body > div,
#content {
  max-width: none;
  width: auto;
}

article, .content, main {
  max-width: calc(var(--measure) + var(--margin-col) + var(--gap));
  margin-inline: auto;
  padding-inline: var(--pad);
}

article > *,
.content > * {
  max-width: var(--measure);
}

/* Full-width figures keep the whole column. */
figure.fullwidth,
.fullwidth,
.gallery {
  max-width: 100%;
  width: 100%;
}


/* --- 5. Headings and prose ----------------------------------------------- */

h1, h2, h3, h4 {
  color: var(--fg-strong);
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-weight: 600;
  margin-block: 2.2em 0.5em;
  text-wrap: balance;
}

h1 { font-size: var(--step-3); margin-block-start: 0; font-weight: 600; }
h2 { font-size: var(--step-2); }
h3 { font-size: var(--step-1); }
h4 { font-size: var(--step-0); letter-spacing: 0; color: var(--muted); }

p { margin-block: 0 1.15em; }

article > h1 + p.subtitle,
.subtitle {
  color: var(--muted);
  font-size: var(--step-1);
  font-family: var(--font-mono);
  margin-block-start: -0.2em;
}

hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin-block: 3rem;
}


/* --- 6. Links, code, quotes, tables -------------------------------------- */

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
  transition: text-decoration-color 0.15s ease, color 0.15s ease;
}
a:hover { text-decoration-color: var(--accent); }

code, kbd, samp {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 0.08em 0.32em;
  font-size: 0.88em;
}

pre {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 1rem 1.2rem;
  overflow-x: auto;
  font-size: var(--step--1);
  line-height: 1.55;
}
pre code { background: none; border: 0; padding: 0; font-size: inherit; }

blockquote {
  border-inline-start: 2px solid var(--accent);
  margin-inline: 0;
  padding-inline-start: 1.2rem;
  color: var(--muted);
  font-style: italic;
}

table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--step--1);
  margin-block: 1.6rem;
}
th, td {
  border-bottom: 1px solid var(--rule);
  padding: 0.5rem 0.7rem;
  text-align: left;
}
th {
  color: var(--muted);
  font-weight: 600;
  letter-spacing: 0;
  font-size: 0.9em;
}

img { max-width: 100%; height: auto; }

/* Math. Hugo renders MathML at build time, so these are real elements and not
   a script's output. A block equation needs its own vertical space, and needs
   to scroll rather than push the page wide on a narrow screen. */
math[display="block"] {
  display: block;
  margin-block: 1.6rem;
  overflow-x: auto;
  overflow-y: hidden;
  font-size: 1.08em;
}
math { font-size: 1.05em; }


/* --- 7. Tufte margin notes and side notes -------------------------------- */

.sidenote, .marginnote {
  color: var(--muted);
  font-size: var(--step--1);
  line-height: 1.5;
}

.marginnote-ind, .sidenote-number {
  color: var(--accent);
  cursor: pointer;
}


/* --- 8. Header, navigation, footer --------------------------------------- */

body > header, .site-header, #brand {
  border-bottom: 1px solid var(--rule);
  margin-bottom: 2.5rem;
}

nav ul, .nav ul, ul.nav {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1.4rem;
  padding: 0;
  margin: 0;
}

nav a {
  color: var(--muted);
  text-decoration: none;
  font-size: var(--step--1);
  letter-spacing: 0;
  padding-block: 0.5rem;
  display: inline-block;
}
nav a:hover { color: var(--fg-strong); }

footer, .page-footer {
  border-top: 1px solid var(--rule);
  margin-top: 4rem;
  padding-block: 1.5rem 3rem;
  color: var(--muted);
  font-size: var(--step--1);
}
.page-footer-menu {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.2rem;
  padding: 0;
}


/* --- 9. Post lists ------------------------------------------------------- */

.post-meta, .content-meta, time {
  color: var(--muted);
  font-size: var(--step--1);
  letter-spacing: 0.03em;
}


/* --- 10. Theme toggle ---------------------------------------------------- */

.theme-toggle {
  background: var(--surface);
  color: var(--fg);
  border: 1px solid var(--rule);
  border-radius: 100px;
  padding: 0.3rem 0.8rem;
  font-size: var(--step--1);
  cursor: pointer;
  line-height: 1.4;
}
.theme-toggle:hover { border-color: var(--accent); color: var(--accent); }


/* --- 10b. Intro and article stubs --------------------------------------- */

.intro {
  max-width: var(--measure);
  margin-bottom: 3rem;
}
.intro > :first-child { margin-block-start: 0; }

/* The stub list spans the full content column, so its edges line up with the
   header underline above it. */
.stubs {
  max-width: none;
  margin-block: 2.5rem 1rem;
}

.stubs-heading {
  font-size: var(--step--1);
  color: var(--muted);
  font-weight: 600;
  letter-spacing: 0;
  margin: 0 0 1.2rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule);
}

.stub {
  display: flex;
  align-items: stretch;
  gap: 1.1rem;
  padding: 1.1rem 0;
  border-bottom: 1px solid var(--rule);
  max-width: none;
}
.stub:last-child { border-bottom: 0; }

/* The square thumbnail.

   Width and height are both set from one token, so the box is square whatever
   the layout does. An earlier version used `align-self: stretch` with an
   aspect ratio, to make the square match the text height exactly. That is not
   reliable: flex resolves the width before the stretched height is known, so
   there was no height to derive a width from and the box came out a
   rectangle. One token on both axes cannot fail.

   The size is tuned to sit close to the height of a title and a two-line
   summary, which is what the clamp on `.stub-sub` keeps it to. */
.stub-media {
  flex: 0 0 auto;
  align-self: center;
  width: var(--stub-square);
  height: var(--stub-square);
  border-radius: 3px;
  overflow: hidden;
  display: block;
  line-height: 0;
  background: var(--surface);
}
.stub-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;   /* crops the photograph to the square */
  object-position: center;
  display: block;
  transition: transform 0.25s ease;
}

.stub-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  justify-content: center;
}

.stub-title {
  margin: 0;
  font-size: var(--step-1);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.stub-title a { color: var(--fg-strong); text-decoration: none; }
.stub-title a:hover { color: var(--accent); }

.stub-sub {
  margin: 0;
  color: var(--muted);
  font-size: var(--step-0);
  line-height: 1.5;
  max-width: 68ch;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.stub-meta {
  margin: 0.15rem 0 0;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--muted);
  display: flex;
  gap: 0.9rem;
  flex-wrap: wrap;
}
.stub-section::after { content: ""; }

.stub-empty { color: var(--muted); }

@media (max-width: 560px) {
  .stub { gap: 0.9rem; }
  .stub-media { width: 4rem; height: 4rem; }
}


/* --- 11. Gallery and lightbox -------------------------------------------- */

.gallery {
  display: grid;
  /* minmax(0, 1fr), never plain 1fr. A `1fr` track has a min-content floor, and
     these items hold 600px images, so plain `1fr` refuses to shrink and pushes
     the whole page wider than a phone screen. */
  grid-template-columns: repeat(var(--gallery-cols, 3), minmax(0, 1fr));
  gap: 1.1rem;
  margin-block: 2.2rem;
  padding: 0;
  list-style: none;
}
@media (max-width: 760px) { .gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 430px) { .gallery { grid-template-columns: minmax(0, 1fr); } }

.gallery-item { margin: 0; padding: 0; width: auto; max-width: none; float: none; min-width: 0; }

.gallery-item > a {
  display: block;
  border-radius: 4px;
  overflow: hidden;
  line-height: 0;
}

.gallery-item img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  transition: transform 0.25s ease, opacity 0.2s ease;
}
.gallery-item > a:hover img { transform: scale(1.03); opacity: 0.92; }

/* The short description under the thumbnail.

   The theme floats every figcaption into the right margin, which is how Tufte
   draws a margin note. See tufte.scss:236. A gallery caption belongs under its
   own photograph, so the float is reset here. Without this reset the caption
   lands under the NEXT photograph in the grid. */
.gallery-caption {
  float: none;
  clear: none;
  margin: 0.55rem 0 0;
  width: auto;
  max-width: none;
  display: block;
  font-size: var(--step--1);
  line-height: 1.4;
  color: var(--muted);
  text-align: left;
}

/* --- Lightbox: image on the left, text panel on the right --- */

.lightbox {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 200;
  background: color-mix(in srgb, var(--bg) 92%, #000);
  backdrop-filter: blur(3px);
}
.lightbox:target { display: grid; }

.lightbox:target {
  grid-template-columns: minmax(0, 1fr) clamp(260px, 26vw, 380px);
  grid-template-rows: 100%;
}

.lightbox-backdrop {
  position: absolute;
  inset: 0;
  cursor: zoom-out;
  z-index: 0;
}

/* The theme caps every figure at 55% width with a 3em bottom margin. See
   tufte.scss:224. A lightbox figure must fill its half of the screen, so both
   are reset here. Without the reset the photograph shows at just over half the
   space it has. */
.lightbox-figure {
  grid-column: 1;
  margin: 0;
  max-width: none;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.75rem, 1.8vw, 1.75rem);
  position: relative;
  z-index: 1;
  pointer-events: none;
}
.lightbox-figure img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 3px;
  box-shadow: 0 8px 40px var(--shadow);
  pointer-events: auto;
}

.lightbox-panel {
  grid-column: 2;
  position: relative;
  z-index: 2;
  background: var(--surface);
  border-inline-start: 1px solid var(--rule);
  padding: clamp(1.4rem, 3vw, 2.2rem);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.8rem;
}
.lightbox-panel h3 {
  margin: 0;
  font-size: var(--step-1);
  letter-spacing: -0.01em;
  color: var(--fg-strong);
}
.lightbox-panel p {
  margin: 0;
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--fg);
}
/* The panel foot pins itself to the bottom and carries the meta line and the
   arrows. */
.lightbox-foot {
  margin-top: auto;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.lightbox-panel .lightbox-meta {
  font-size: var(--step--1);
  color: var(--muted);
  font-family: var(--font-mono);
}

.lightbox-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
}

.lightbox-nav a {
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border: 1px solid var(--rule);
  border-radius: 100px;
  color: var(--fg);
  text-decoration: none;
  font-size: 1.05rem;
  line-height: 1;
  flex: none;
}
.lightbox-nav a:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.lightbox-count {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.lightbox-close {
  position: absolute;
  top: 0.8rem;
  right: 0.9rem;
  z-index: 3;
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  border-radius: 100px;
  background: var(--surface);
  border: 1px solid var(--rule);
  color: var(--fg);
  font-size: 1.2rem;
  line-height: 1;
  text-decoration: none;
}
.lightbox-close:hover { color: var(--accent); border-color: var(--accent); }

/* Narrow screens: image on top, text below. */
@media (max-width: 720px) {
  .lightbox:target {
    grid-template-columns: 1fr;
    grid-template-rows: minmax(0, 1fr) auto;
  }
  .lightbox-figure { grid-column: 1; grid-row: 1; padding: 0.75rem; height: 100%; }
  .lightbox-figure img { max-height: 100%; }
  .lightbox-panel {
    grid-column: 1;
    grid-row: 2;
    border-inline-start: 0;
    border-top: 1px solid var(--rule);
    max-height: 42vh;
  }
}


::selection {
  background: color-mix(in srgb, var(--accent) 28%, transparent);
  color: var(--fg-strong);
}


/* --- 12. Accessibility and print ----------------------------------------- */

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  :root { --bg: #fff; --fg: #000; --muted: #444; --rule: #ccc; }
  nav, .theme-toggle, .lightbox { display: none !important; }
  a { text-decoration: none; color: #000; }
}


/* --- 13. Brand header (site title, subtitle, nav, toggle) ---------------- */

.brand {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem 2rem;
  max-width: calc(var(--measure) + var(--margin-col) + var(--gap));
  margin-inline: auto;
  padding: 2.2rem var(--pad) 1.1rem;
  margin-bottom: 2.8rem;
  position: relative;
}

/* The underline is drawn inset by --pad, not across the whole header box, so
   its left edge sits under the site title and under the stubs below it. */
.brand::after {
  content: "";
  position: absolute;
  left: var(--pad);
  right: var(--pad);
  bottom: 0;
  height: 1px;
  background: var(--rule);
}

.brand-id { min-width: 0; }

.brand h1 {
  font-size: var(--step-1);
  margin: 0;
  font-weight: 600;
  letter-spacing: -0.01em;
  font-family: var(--font-mono);
}
.brand h1 a { color: var(--fg-strong); text-decoration: none; }
.brand h1 a:hover { color: var(--accent); }

.brand .subtitle {
  margin: 0.25rem 0 0;
  font-size: var(--step--1);
  color: var(--muted);
  font-family: var(--font-mono);
}

/* The theme sets `.menu ul { display: block; width: 87.5% }` in nav.scss, and
   a class selector beats a bare element selector. That wide block list pushed
   the theme toggle onto a second row. These overrides match the theme's own
   specificity so they win. */
nav.menu {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.4rem 1.4rem;
  flex-wrap: wrap;
}

.menu ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 1.4rem;
  width: auto;
  max-width: none;
  font-size: inherit;
  padding: 0;
  margin: 0;
  list-style: none;
}

.menu li { display: inline-block; margin-right: 0; }

/* Sentence case. The theme uppercases nav links in nav.scss and table headers
   in tufte.scss. Both selectors carry a class, so a bare `nav a` loses. */
.menu li a,
table:not(.lntable) tr th,
table th {
  text-transform: none;
  letter-spacing: 0;
}

nav a[aria-current="page"] { color: var(--fg-strong); }

/* The toggle names the mode it switches TO. */
[data-theme="dark"] .theme-toggle-light,
.theme-toggle-dark { display: none; }
[data-theme="dark"] .theme-toggle-dark { display: inline; }

.lightbox-empty { color: var(--muted); font-size: var(--step--1); }
