/* ==========================================================================
   The Snowball
   A single-family investment office
   --------------------------------------------------------------------------
   Direction: washi & indigo. Warm kozo-paper ground, sumi ink, a single
   deep aizome indigo. Latin in Newsreader (variable optical size, so the
   display sizes sharpen toward the thin-horizontal / thick-vertical contrast
   of Mincho). Japanese in Noto Serif JP, falling back to the Mincho faces
   already installed on Japanese machines.
   ========================================================================== */

/* --- Faces --------------------------------------------------------------- */

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 200 600;
  font-display: swap;
  src: url('fonts/newsreader-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
    U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Noto Serif JP, subset to exactly the glyphs these two pages use. The
   unicode-range is deliberately narrow: anything outside it falls through to
   the Mincho faces already installed on Japanese machines rather than
   rendering as tofu. Regenerate with `npm run fonts:ja` after editing copy. */
@font-face {
  font-family: 'Noto Serif JP';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('fonts/noto-serif-jp-subset.woff2') format('woff2');
  unicode-range: U+a9, U+2014, U+3001-3002, U+3005, U+3042, U+3044, U+3046,
    U+3048, U+304a-306b, U+306d-3074, U+3078-307f, U+3081-3083, U+3088-308c,
    U+308f, U+3092-3094, U+3099-309a, U+30a3, U+30aa, U+30ad-30ae,
    U+30b5-30ba, U+30c6-30c7, U+30d8-30da, U+30f3, U+30fc, U+4e00, U+4e0a,
    U+4e2d, U+4e8b-4e8c, U+4eba, U+4ee3, U+4f1a, U+4f4d, U+4fdd, U+4fe1,
    U+500b, U+5074, U+511f, U+5148, U+5165, U+5229, U+52d5, U+5341, U+534a,
    U+5358, U+53ca, U+5408, U+554f, U+55b6, U+56db, U+56fd, U+5728, U+5730,
    U+5805, U+5831, U+5834, U+5916, U+591a, U+59d4, U+5b58, U+5b9a, U+5bb6,
    U+5bfe, U+5c11, U+5dde, U+5df1, U+5e74, U+5e78, U+5f15, U+5f37, U+5fc3,
    U+5fcd, U+5fdc, U+5ff5, U+6025, U+6050, U+610f, U+6240, U+624b, U+627f,
    U+6295, U+6301, U+6307, U+63da, U+652f, U+653e, U+6570, U+6574, U+65b9,
    U+65cf, U+65e5, U+6708-6709, U+671f, U+672c, U+696d, U+6982, U+6a21,
    U+6c42, U+6df1, U+7248, U+7387, U+7406, U+7523, U+7528, U+7533, U+793e,
    U+79c1, U+7acb, U+7c73, U+7d4c, U+7d5e, U+7d61, U+7d99-7d9a, U+8003,
    U+8010, U+81ea, U+82f1, U+884c, U+8868, U+8907, U+8981, U+898f, U+89e3,
    U+8a2d, U+8a6b, U+8a9e, U+8aa0, U+8cc7, U+8cdc, U+9023, U+904b, U+9078,
    U+9084, U+90e8, U+91d1, U+91dd, U+9577, U+9589, U+9593, U+9650, U+96c6,
    U+975e, U+983c, U+ff5c;
}

/* --- Tokens -------------------------------------------------------------- */

:root {
  /* Paper and ink */
  --washi:        #f1ede2;
  --washi-rim:    #e6e0d0;
  --sumi:         #14110c;
  --sumi-quiet:   #55503f;
  --ai:           #1b3a63;

  /* Rules. Indigo rather than grey, so every line on the page reads as
     blind-embossed into the paper rather than printed on top of it. */
  --rule:         rgba(27, 58, 99, .20);
  --rule-soft:    rgba(27, 58, 99, .11);

  /* Faces */
  --lat: 'Newsreader', Georgia, 'Times New Roman', serif;
  --ja: 'Noto Serif JP', 'Hiragino Mincho ProN', 'Hiragino Mincho Pro',
        'Yu Mincho', YuMincho, 'Yu Mincho Medium', 'MS Mincho', serif;

  /* Measure */
  --shell: 61rem;
  --gutter: clamp(1.5rem, 6vw, 5.5rem);
  --label-col: 11.5rem;

  /* 間 — the vertical silences between movements */
  --ma-lg: clamp(7rem, 17vh, 13.5rem);
  --ma-md: clamp(3.25rem, 7vh, 5.5rem);

  --ease: cubic-bezier(.16, 1, .3, 1);
}

/* --- Reset --------------------------------------------------------------- */

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

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

body {
  position: relative; /* the hill is measured against the document box */
  background: var(--washi);
  color: var(--sumi);
  font-family: var(--lat);
  font-size: clamp(1rem, .97rem + .16vw, 1.0938rem);
  font-weight: 380;
  line-height: 1.72;
  font-variant-numeric: oldstyle-nums;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Japanese wants a smaller optical size and considerably more leading than
   Latin at the same nominal point size. */
html[lang='ja'] body {
  font-family: var(--ja);
  font-size: clamp(.9375rem, .91rem + .14vw, 1.0313rem);
  font-weight: 400;
  line-height: 2.05;
  font-variant-numeric: normal;
}

/* Latin runs inside Japanese text — the wordmark, the address, the year. */
.lat { font-family: var(--lat); font-variant-numeric: oldstyle-nums; }

a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
  transition: border-color .5s var(--ease), color .5s var(--ease);
}
a:hover { color: var(--ai); border-bottom-color: var(--ai); }

:focus-visible {
  outline: 1.5px solid var(--ai);
  outline-offset: 4px;
  border-radius: 1px;
}

/* --- The paper ----------------------------------------------------------- */
/* Two turbulence layers: a fine grain, and a horizontally-stretched one that
   reads as the long kozo fibres suspended in real washi. Plus the faint
   regular lines left by the su screen the sheet was couched on. */

.paper {
  position: fixed;
  inset: 0;
  z-index: 5; /* over the type as well — ink sits in the paper, not on it */
  pointer-events: none;
  mix-blend-mode: multiply;
  opacity: .3;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23f)' opacity='.5'/%3E%3C/svg%3E"),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='900'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.0022 .45' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='900' height='900' filter='url(%23g)' opacity='.14'/%3E%3C/svg%3E");
  background-size: 300px 300px, 900px 900px;
}

/* --- The hill ------------------------------------------------------------ */
/* A snowball needs wet snow and a long hill. The hill is one hairline
   descending the entire length of the document, behind everything; the
   snowball rides it as you read, gaining a little size on the way down.
   It is meant to be noticed second, not first. */

.hill {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}
/* The line is a track, not a route: it is drawn only where the snowball has
   already been. Nothing waits ahead of it. */
.hill path {
  fill: none;
  stroke: var(--ai);
  stroke-width: 1;
  stroke-opacity: .1; /* must disappear under body text; the ball carries it */
  vector-effect: non-scaling-stroke;
}
.snowball {
  position: absolute;
  z-index: 0; /* behind the shell, so it slides under the seal at the foot */
  top: 0;
  left: 0;
  border-radius: 50%;
  background: var(--ai);
  opacity: .5;
  pointer-events: none;
  will-change: transform;
}

/* --- Shell --------------------------------------------------------------- */

.shell {
  position: relative;
  z-index: 1;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* --- Masthead ------------------------------------------------------------ */

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
  padding-block: clamp(1.75rem, 4vh, 3rem) 1.25rem;
  border-bottom: 1px solid var(--rule);
}

/* The wordmark block is the page's h1; it should carry no default heading
   styling of its own. */
.brand { font: inherit; }

.wordmark {
  font-family: var(--lat);
  font-size: clamp(1.0625rem, 1rem + .35vw, 1.3125rem);
  font-weight: 400;
  letter-spacing: .1em;
  line-height: 1;
  color: var(--sumi);
}

.standing-line {
  display: block;
  margin-top: .75em;
  font-size: .6875rem;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--sumi-quiet);
}
html[lang='ja'] .standing-line {
  font-size: .75rem;
  letter-spacing: .16em;
  text-transform: none;
}

/* --- Language switch ----------------------------------------------------- */

.switch {
  flex: none;
  font-size: .75rem;
  letter-spacing: .12em;
  color: var(--ai);
  border-bottom-color: var(--rule-soft);
  white-space: nowrap;
}
.switch:hover { border-bottom-color: var(--ai); }

/* --- Movements ----------------------------------------------------------- */

/* Spacing lives on the leading edge only, so the silence between two
   movements is one interval rather than two stacked on each other. */
.movement { padding-block: var(--ma-lg) 0; }
.movement--opening { padding-block: clamp(5rem, 17vh, 11rem) 0; }
main.shell { padding-bottom: var(--ma-lg); }

/* The opening statement. Two beats: the declaration, then — after a pause —
   the promise. The pause is the point. */

.statement {
  font-size: clamp(1.5rem, 1.02rem + 2.15vw, 2.9rem);
  font-weight: 300;
  line-height: 1.34;
  letter-spacing: -.014em;
  max-width: 27ch;
  text-wrap: pretty;
  hyphens: none;
}
.statement + .statement { margin-top: .55em; }
.statement--coda { color: var(--ai); }

html[lang='ja'] .statement {
  font-size: clamp(1.25rem, .95rem + 1.35vw, 2.05rem);
  font-weight: 400;
  line-height: 1.86;
  letter-spacing: .01em;
  max-width: 23em; /* ~23 characters — a classic Japanese display measure */
}

/* --- Section headings ---------------------------------------------------- */

.movement > h2 {
  display: flex;
  align-items: baseline;
  gap: 1em;
  padding-bottom: .9rem;
  margin-bottom: var(--ma-md);
  border-bottom: 1px solid var(--rule);
  font-size: .6875rem;
  font-weight: 400;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--sumi-quiet);
}
.movement > h2 .gloss {
  font-family: var(--ja);
  font-size: .8125rem;
  letter-spacing: .14em;
  text-transform: none;
  color: var(--ai);
  opacity: .75;
}
html[lang='ja'] .movement > h2 {
  font-family: var(--ja);
  font-size: .8125rem;
  letter-spacing: .22em;
  text-transform: none;
}
html[lang='ja'] .movement > h2 .gloss {
  font-family: var(--lat);
  font-size: .625rem;
  letter-spacing: .2em;
  text-transform: uppercase;
}

/* --- Body prose ---------------------------------------------------------- */

/* Body prose is indented into the document column, so that every line of
   reading matter on the page shares one left edge. Only the opening
   statement breaks it — which is why the opening statement lands. */
.prose {
  max-width: 46ch;
  margin-left: calc(var(--label-col) + 2.5rem);
  color: var(--sumi);
}
html[lang='ja'] .prose { max-width: 36em; }

/* --- Principles ---------------------------------------------------------- */
/* Each principle carries its name in the margin, in the manner of a 頭注 —
   a marginal gloss. The margin says what the principle is about; the column
   says what we do about it. (Kanji numerals were tried here and abandoned:
   一 二 三 are almost entirely whitespace while 四 is dense, so the column
   read as broken rather than enumerated.) */

.principles { list-style: none; }

.principle {
  display: grid;
  grid-template-columns: var(--label-col) minmax(0, 1fr);
  gap: 0 2.5rem;
  padding-block: clamp(1.5rem, 3.5vh, 2.5rem);
  border-top: 1px solid var(--rule-soft);
}
.principle:first-child { border-top: 0; padding-top: 0; }

/* Shares its treatment with the particulars terms, so every gloss in the
   left column of the document reads as one voice. */
.principle__name,
.particular dt {
  font-size: .6875rem;
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--sumi-quiet);
  line-height: 2.55;
}
html[lang='ja'] .principle__name,
html[lang='ja'] .particular dt {
  font-family: var(--ja);
  font-size: .8125rem;
  letter-spacing: .16em;
  text-transform: none;
  line-height: 2.15;
}

.principle__text { max-width: 46ch; }
html[lang='ja'] .principle__text { max-width: 36em; }

/* --- Particulars --------------------------------------------------------- */

.particulars { display: grid; gap: 0; }

.particular {
  display: grid;
  grid-template-columns: var(--label-col) minmax(0, 1fr);
  gap: 0 2.5rem;
  padding-block: 1.05rem;
  border-top: 1px solid var(--rule-soft);
}
.particular:first-child { border-top: 0; }

.particular dd { font-size: 1.0625rem; }
html[lang='ja'] .particular dd { font-size: 1rem; }

.note {
  margin-top: var(--ma-md);
  margin-left: calc(var(--label-col) + 2.5rem);
  max-width: 46ch;
  font-size: .9375rem;
  color: var(--sumi-quiet);
}
html[lang='ja'] .note { max-width: 36em; font-size: .9375rem; }

/* --- The seal ------------------------------------------------------------ */
/* A hand-cut stone seal closes the document, as it would close a Japanese
   one. The knocked-out circle is the snowball, and it is also 円. */

.seal-row {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--ma-md);
}
.seal {
  width: 46px;
  height: 46px;
  transform: rotate(-1.5deg);
  opacity: .9;
}
.seal rect, .seal path { fill: var(--ai); }
.seal circle { fill: var(--washi); }

/* --- 縦書き marginalia ---------------------------------------------------- */
/* One vertically-set line in the outer margin, in the manner of a 頭注.
   Hidden below the width where it would have to intrude on the text. */

.marginalia {
  position: absolute;
  top: clamp(4rem, 9vh, 7rem);
  right: calc(var(--gutter) * -1 + .5rem);
  writing-mode: vertical-rl;
  font-family: var(--ja);
  font-size: .75rem;
  font-weight: 400;
  letter-spacing: .42em;
  color: var(--ai);
  opacity: .38;
  user-select: none;
  pointer-events: none;
}

/* --- Colophon ------------------------------------------------------------ */

.colophon {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
  padding-block: 1.25rem clamp(2rem, 5vh, 3.5rem);
  border-top: 1px solid var(--rule);
  font-size: .75rem;
  letter-spacing: .1em;
  color: var(--sumi-quiet);
}

/* --- Language notice ----------------------------------------------------- */
/* Shown only to visitors whose browser is set to Japanese and who have landed
   on the English page. Offered, never forced — no redirect. */

.notice {
  position: relative;
  z-index: 2;
  display: none;
  align-items: baseline;
  justify-content: center;
  gap: 1.5rem;
  padding: .85rem var(--gutter);
  border-bottom: 1px solid var(--rule);
  background: var(--washi-rim);
  font-family: var(--ja);
  font-size: .8125rem;
  letter-spacing: .04em;
}
.notice[data-open='true'] { display: flex; }
.notice a { border-bottom-color: var(--ai); color: var(--ai); }
.notice button {
  flex: none;
  border: 0;
  background: none;
  font: inherit;
  font-size: .75rem;
  color: var(--sumi-quiet);
  cursor: pointer;
  padding: .2rem .35rem;
}
.notice button:hover { color: var(--sumi); }

/* --- Entrances ----------------------------------------------------------- */

/* Scoped to .js so that without JavaScript the page simply renders, rather
   than rendering nothing at all. */
.js .rise {
  opacity: 0;
  transform: translateY(1.35rem);
  transition: opacity 1.1s var(--ease), transform 1.1s var(--ease);
}
.js .rise.is-in { opacity: 1; transform: none; }

/* Page-load sequence: masthead, then the declaration, then the promise. */
.lead-1 { transition-delay: .15s; }
.lead-2 { transition-delay: .55s; }
.lead-3 { transition-delay: 1.15s; }

/* --- Narrow -------------------------------------------------------------- */

@media (max-width: 62rem) {
  .marginalia { display: none; }
}

@media (max-width: 44rem) {
  .masthead { flex-direction: column; align-items: flex-start; gap: 1.25rem; }

  .statement { max-width: none; }

  .prose, .note { margin-left: 0; }

  .principle,
  .particular {
    grid-template-columns: minmax(0, 1fr);
    gap: .5rem;
  }
  .principle__name, .particular dt { line-height: 1.9; }

  .colophon { flex-direction: column; gap: .6rem; }
}

/* --- Reduced motion ------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .rise { opacity: 1; transform: none; transition: none; }
  .snowball { transition: none; }
  *, *::before, *::after { animation-duration: .01ms !important; }
}

/* --- Print --------------------------------------------------------------- */
/* They will print this, or paste it into a document. It should survive both. */

@media print {
  @page { margin: 18mm; }

  /* The rhythm tokens are viewport-derived, which is meaningless on paper.
     Restate them in millimetres so the sheet is set, not scaled. */
  :root {
    --rule: rgba(0, 0, 0, .35);
    --rule-soft: rgba(0, 0, 0, .18);
    --ma-lg: 13mm;
    --ma-md: 6mm;
  }

  body { background: #fff; color: #000; font-size: 10.5pt; line-height: 1.6; }

  .paper, .hill, .snowball, .notice, .switch,
  .marginalia { display: none !important; }

  .shell { max-width: none; padding-inline: 0; }
  .rise { opacity: 1 !important; transform: none !important; }

  /* Leading-edge spacing only, as on screen. break-inside on the movement
     itself would shunt a whole section to the next sheet; the rows below are
     the right granularity. */
  .movement { padding-block: var(--ma-lg) 0; }
  .movement--opening { padding-block: 0; }
  main.shell { padding-bottom: 10mm; }

  .statement,
  html[lang='ja'] .statement { font-size: 15pt; max-width: 34em; }
  .statement--coda { color: #000; }

  .principle, .particular { break-inside: avoid; }
  .movement > h2 { break-after: avoid; }
  .principle__name, .movement > h2 .gloss { color: #000; }

  .seal rect, .seal path { fill: #000; }
  .seal circle { fill: #fff; }

  a { border-bottom: 0; }
  .colophon a[href^='http']::after { content: ' (' attr(href) ')'; }
}
