/* ============================================================================
   BOSATSU — site components
   ----------------------------------------------------------------------------
   Built only against the tokens in theme.css. No literal colours, no literal
   font families. Swap the theme and this all follows.
   ============================================================================ */

/* ---------------------------------------------------------------- shell --- */

.page {
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: clamp(var(--space-s), 5vw, var(--space-l));
}

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  flex-wrap: wrap;
  padding-block: var(--space-s);
  border-bottom: 1px solid var(--rule);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  border: 0;
  color: inherit;
}
.brand:hover { border: 0; }

.brand__name {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  line-height: 1.2;
}
.brand__qualifier {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* nav: the active page is marked with a small vermilion stamp, tying wayfinding
   to the signature rather than inventing a second visual language for it. */
.site-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
}
.site-nav a {
  font-size: 0.9375rem;
  color: var(--fg);
  border: 0;
  padding-block: var(--space-2xs);
  position: relative;
}
.site-nav a:hover { color: var(--accent); border: 0; }
.site-nav a[aria-current="page"] { color: var(--fg); }
.site-nav a[aria-current="page"]::before {
  content: "";
  position: absolute;
  inset-inline-start: -0.6rem;
  inset-block-start: 50%;
  translate: 0 -50%;
  inline-size: 3px;
  block-size: 3px;
  background: var(--seal);
  border-radius: 1px;
}

.site-footer {
  margin-block-start: var(--space-2xl);
  padding-block: var(--space-m);
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s) var(--space-m);
  align-items: baseline;
  justify-content: space-between;
  font-size: 0.9375rem;
  color: var(--muted);
}
.site-footer ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-s); }

/* section rhythm — one rule, applied once, so nothing cancels out */
.section { padding-block-start: var(--space-xl); }
.section + .section { padding-block-start: var(--space-xl); }
.section__head { margin-block-end: var(--space-m); }

/* ----------------------------------------------------------------- hero --- */
/* The thesis, not a banner. Portrait is subordinate: a quiet column beside the
   words, never a full-bleed image — full-bleed would spend the restraint the
   rest of the page depends on. */

.hero {
  padding-block: clamp(var(--space-l), 9vw, var(--space-2xl)) var(--space-l);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(var(--space-m), 6vw, var(--space-xl));
  align-items: start;
}

.hero__seal { margin-block-end: var(--space-m); }

.hero__title {
  font-size: clamp(2.2rem, 1.3rem + 3.2vw, 3.6rem);
  margin-block-end: var(--space-s);
}

.hero__thesis {
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  color: var(--muted);
  max-width: 32rem;
  margin-block-end: var(--space-m);
}

/* The brand bar: a held-greige vertical column carrying the three glyphs
   (writing · seal · speaking) on transparent grounds. Greige in both themes —
   a calm, constant brand block rather than a photograph. */
.hero__bar {
  inline-size: clamp(9rem, 18vw, 12rem);
  align-self: stretch;              /* fill the hero row: a true vertical bar */
  min-block-size: 22rem;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 2px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-evenly;
  gap: var(--space-m);
  padding: var(--space-l) var(--space-m);
}
.hero__bar img {
  inline-size: auto;
  max-inline-size: 100%;
  object-fit: contain;
}
/* The two kanji columns (first + last) read largest; the seal in the middle is
   sized up too, but kept a step smaller so it doesn't crowd them. */
.hero__bar img:first-child,
.hero__bar img:last-child { block-size: clamp(6.5rem, 15vw, 9rem); }
.hero__bar img:nth-child(2) { block-size: clamp(5.25rem, 12vw, 7rem); }

@media (max-width: 46rem) {
  .hero { grid-template-columns: minmax(0, 1fr); }
  /* The brand bar is a subordinate, decorative aside (aria-hidden). It only
     reads as intended when it can stand as a tall column beside the words;
     laid down into a phone-width band it looked cramped and off. Rather than
     ship a compromised version, drop it below the single-column breakpoint —
     the thesis carries the hero on its own. */
  .hero__bar { display: none; }
}


/* --------------------------------------------------------------- actions - */

.actions { display: flex; flex-wrap: wrap; gap: var(--space-s); align-items: center; }

.button {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  font-size: 0.9375rem;
  padding: var(--space-2xs) var(--space-s);
  border: 1px solid var(--accent);
  border-radius: 2px;
  color: var(--accent);
  background: transparent;
  transition: background 140ms ease, color 140ms ease;
}
.button:hover { background: var(--accent); color: var(--bg); border-color: var(--accent); }

/* ------------------------------------------------------------- practice --- */
/* Five engagements. Deliberately NOT numbered: they're alternatives you choose
   between, not a sequence you move through, so numbering would assert an order
   that isn't true. Hairline-ruled rows instead of cards — cards would add five
   boxes to a page whose whole argument is negative space. */

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

.practice > li {
  border-top: 1px solid var(--rule);
  padding-block: var(--space-m);
  display: grid;
  grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr);
  gap: var(--space-s) clamp(var(--space-m), 5vw, var(--space-l));
  align-items: start;
}
.practice > li:last-child { border-bottom: 1px solid var(--rule); }

.practice h3 { margin: 0; }
.practice p { margin: 0; color: var(--muted); }

@media (max-width: 46rem) {
  .practice > li { grid-template-columns: minmax(0, 1fr); gap: var(--space-xs); }
}

/* --------------------------------------------------------------- topics --- */
/* The utility face carrying the breadth claim. Set as a dense field rather than
   a list: the point is the extent of it, read at a glance. */

.topics {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-xs);
  max-width: 52rem;
}
.topics li {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--muted);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0.15rem var(--space-2xs);
  white-space: nowrap;
}

/* ---------------------------------------------------------------- works --- */

.works { list-style: none; margin: 0; padding: 0; }
.works > li {
  border-top: 1px solid var(--rule);
  padding-block: var(--space-s);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-s);
  align-items: baseline;
  justify-content: space-between;
}
.works > li:last-child { border-bottom: 1px solid var(--rule); }
.works h2 { font-size: 1.1875rem; font-weight: 500; }
.works h2 a { color: var(--fg); border: 0; }
.works h2 a:hover { color: var(--accent); }
.works__year { font-family: var(--font-mono); font-size: 0.8125rem; color: var(--muted); }

/* ---------------------------------------------------------------- talks --- */

.talks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--space-m);
}
.talk__thumb {
  inline-size: 100%;
  block-size: auto;          /* let aspect-ratio set height, not the height attr */
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 2px;
  border: 1px solid var(--rule);
  margin-block-end: var(--space-xs);
  /* Held greyscale so an external video still doesn't break the B&W photo set;
     blooms to colour on hover/focus, so the thumbnail stays recognisable. */
  filter: grayscale(1) contrast(1.02);
  transition: filter 220ms ease;
}
.talk a:hover .talk__thumb,
.talk a:focus-visible .talk__thumb { filter: grayscale(0); }
.talk h3 { margin-block-end: var(--space-2xs); font-size: 1.0625rem; }
.talk p { margin: 0; font-size: 0.9375rem; color: var(--muted); }

/* --------------------------------------------------------------- figure --- */

.figure { margin: 0; }
.figure img {
  inline-size: 100%;
  border-radius: 2px;
  border: 1px solid var(--rule);
  filter: saturate(0.92);
}
.figure figcaption {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--muted);
  margin-block-start: var(--space-2xs);
}

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--space-m);
}

/* -------------------------------------------------------------- contact --- */

.contact-list { list-style: none; margin: 0; padding: 0; }
.contact-list li { padding-block: var(--space-2xs); }
.contact-list .label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
}

/* ---------------------------------------------------------------- tags --- */
/* The shared vocabulary made visible. A topic chip carries the same small
   vermilion stamp the nav uses for the current page — the one warm gesture,
   reused as a wayfinding mark, never as decoration. */

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-xs);
  margin-block-start: var(--space-s);
}
.tag {
  display: inline-flex;
  align-items: center;
  min-block-size: 1.5rem;          /* 24px — WCAG 2.5.8 target size */
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--muted);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 0.1rem var(--space-2xs);
  white-space: nowrap;
  line-height: 1.4;
}
a.tag:hover { color: var(--accent); border-color: var(--accent); }
.tag--topic { color: var(--fg); }
.tag--topic::before {
  content: "";
  display: inline-block;
  inline-size: 4px;
  block-size: 4px;
  border-radius: 1px;
  background: var(--seal);
  margin-inline-end: 0.45em;
}

/* -------------------------------------------------------------- events --- */
/* Upcoming talks. Date column left, detail right — the same hairline-ruled row
   rhythm as the engagements list, so Speaking and Practice feel of a piece. */

.events { list-style: none; margin: 0; padding: 0; }
.event {
  border-top: 1px solid var(--rule);
  padding-block: var(--space-m);
  display: grid;
  grid-template-columns: minmax(7rem, 10rem) minmax(0, 1fr);
  gap: var(--space-xs) clamp(var(--space-m), 5vw, var(--space-l));
  align-items: baseline;
}
.event:last-child { border-bottom: 1px solid var(--rule); }
.event__when time {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--fg);
  letter-spacing: 0.02em;
}
.event__what h3 { margin: 0 0 var(--space-2xs); font-size: 1.1875rem; }
.event__venue { margin: 0 0 var(--space-2xs); color: var(--fg); }
.event__meta { margin: 0; color: var(--muted); font-size: 0.9375rem; }
.event__desc { margin-block-start: var(--space-xs); color: var(--muted); }
.event .tags { margin-block-start: var(--space-xs); }
@media (max-width: 46rem) {
  .event { grid-template-columns: minmax(0, 1fr); gap: var(--space-2xs); }
}

/* ------------------------------------------------------------ projects --- */

.projects { list-style: none; margin: 0; padding: 0; }
.project {
  border-top: 1px solid var(--rule);
  padding-block: var(--space-l);
}
.project:last-child { border-bottom: 1px solid var(--rule); }
.project__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-s);
  flex-wrap: wrap;
}
.project__head h2 { font-size: 1.5rem; }
.project__status { font-size: 0.75rem; color: var(--muted); }
.project__tagline {
  font-family: var(--font-display);
  font-size: 1.1875rem;
  color: var(--muted);
  max-width: none;
  margin-block: var(--space-2xs) var(--space-s);
}
.project__links { font-family: var(--font-mono); font-size: 0.8125rem; margin-block-start: var(--space-s); }

/* A project with a logo lays out two columns: text left, mark right. */
.project--logo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(9rem, 16rem);
  gap: clamp(var(--space-m), 5vw, var(--space-l));
  align-items: center;                 /* centre the mark against the text */
}
.project__logo {
  margin: 0;
  display: grid;
  place-items: center;                 /* centre the mark within its column */
}
.project__logo img {
  inline-size: clamp(8rem, 18vw, 12rem);
  block-size: auto;
}
@media (max-width: 46rem) {
  .project--logo { grid-template-columns: minmax(0, 1fr); }
  .project__logo { order: -1; justify-items: start; }
  .project__logo img { inline-size: 7rem; }
}

/* ----------------------------------------------------- anchored topics --- */
/* Each subject is an anchor target, so a tag on a note or a talk can jump the
   reader straight to it. Arriving via that link lights the chip briefly. */

.topics li { display: inline-flex; align-items: baseline; gap: 0.4em; }
.topics__count { color: var(--warm); border: 0; }
a.topics__count:hover { color: var(--accent); }
.topics li:target {
  border-color: var(--accent);
  color: var(--fg);
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  scroll-margin-block-start: var(--space-l);
}

/* ---------------------------------------------------------- media band --- */
/* Full page-width photograph. Used on Speaking, never on the home page: a
   full-bleed image there would spend the restraint the rest of the site keeps. */

.media-band { margin: var(--space-m) 0 0; }
.media-band img {
  inline-size: 100%;
  block-size: auto;
  display: block;
  border-radius: 2px;
  border: 1px solid var(--rule);
  filter: saturate(0.92);
}

/* --------------------------------------------------------- posts teaser --- */
/* The "latest note" block on the home page. Styled here, not in tufte.css,
   because the home page does not load the long-form layer. */

.posts--teaser { list-style: none; margin: 0; padding: 0; }
.posts--teaser > li { border-top: 1px solid var(--rule); padding-block: var(--space-s); }
.posts--teaser h3 { font-size: 1.1875rem; margin-block-end: var(--space-2xs); }
.posts--teaser h3 a { color: var(--fg); border: 0; }
.posts--teaser h3 a:hover { color: var(--accent); }
.posts--teaser p { color: var(--muted); margin-block-end: var(--space-2xs); }
.posts--teaser time { font-family: var(--font-mono); font-size: 0.75rem; color: var(--muted); }

/* ------------------------------------------------------- contact form --- */

.contact-form { max-width: 38rem; margin-block-start: var(--space-m); }
.contact-form__honey { position: absolute !important; left: -9999px; height: 0; overflow: hidden; }
.field { margin-block-end: var(--space-s); }
.field label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-block-end: var(--space-2xs);
}
.field__opt { text-transform: none; letter-spacing: 0; }
/* The list is per-type because a bare `.contact-form input` would also catch the honeypot
   and the submit button. The booking form is GENERATED from the service's description, so
   the types in it are whatever ikigai-forms.js decides — keep this list and that function
   in step, or a new field arrives as an unstyled browser default in the middle of a themed
   form. That is what `date` did until the time inputs landed beside it. */
.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form input[type="number"],
.contact-form input[type="date"],
.contact-form input[type="time"],
.contact-form select,
.contact-form textarea {
  inline-size: 100%;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--fg);
  background: color-mix(in srgb, var(--fg) 3%, transparent);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: var(--space-xs) var(--space-s);
  line-height: 1.5;
}
/* The parts of a date/time field the page cannot paint — the calendar and clock indicators,
   and the panel they open — are drawn by the browser. `light dark` says the field is legible
   either way, so the browser picks the one the visitor's system asked for, which is the same
   preference theme.css switches on. No colour is declared here; that stays theme.css's job. */
.contact-form input[type="date"],
.contact-form input[type="time"] { color-scheme: light dark; }
.contact-form textarea { resize: vertical; }
.contact-form input:focus-visible,
.contact-form select:focus-visible,
.contact-form textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

.button { cursor: pointer; }
button.button { font-family: inherit; }

/* section that sits directly under the header wants less air above it */
.section--tight { padding-block-start: var(--space-l); }

/* ----------------------------------------------------------------- 404 --- */
/* The one page where the seal leads rather than signs off: 不在 stamped above
   the heading, so the answer arrives before the explanation. Everything else
   is the ordinary section rhythm — a dead end should still feel like the
   same building. */
.section--404 > .seal { margin-block-end: var(--space-m); }
.section--404 .section__head { margin-block-start: 0; }
/* the closing line is a separate thought from the three ways out */
.section--404 .actions { margin-block-end: var(--space-m); }

/* ---------------------------------------------------------- htmx states --- */
/* The swap is announced to screen readers by site.js; this is the visual half.
   Kept to opacity only: a spinner would be louder than anything else on the
   page and would break the calm the whole design is buying. */

#main.htmx-swapping { opacity: 0.4; transition: opacity 120ms ease; }
#main.htmx-settling { opacity: 1; }

.htmx-indicator { opacity: 0; transition: opacity 180ms ease; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; }
