/* Kamakura Quant Lab — the public site.
 *
 * One idea runs through this file: colour means you can act on it. Indigo is
 * used for links, buttons, focus rings and pending selections, and for nothing
 * else. Headings, rules and panels are ink and grey. A reader never has to
 * work out whether something is clickable, and the page stays quiet because
 * the only saturated thing on it is the thing you can do.
 *
 * Light only. `color-scheme` is declared so form controls follow.
 */

:root {
  color-scheme: light;

  --page: #ffffff;
  --sunken: #f5f6f8;      /* tool panels, code, inputs at rest */
  --ink: #141b26;         /* sumi: blue-black, not tinted grey */
  --ink-2: #39424f;
  --muted: #5b6472;
  --rule: #dfe3e9;
  --rule-strong: #c2c9d3;

  /* The only colour on the page. */
  --act: #1f3f6e;
  --act-hover: #16305a;
  --act-soft: #eef2f8;
  --visited: #64437f;

  /* Used where the meaning is the colour, and nowhere for emphasis. */
  --good: #1c6b4c;
  --warn: #8a5a08;
  --bad: #9b2b2b;

  --measure: 36rem;       /* ~68 Latin characters, ~36 Japanese */
  --wide: 52rem;       /* the page; see main below */

  --sans: system-ui, -apple-system, "Segoe UI", "Hiragino Kaku Gothic ProN",
          "Hiragino Sans", "Yu Gothic Medium", "Yu Gothic", "Noto Sans JP",
          Meiryo, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font: 16px/1.8 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* Latin runs shorter than Japanese at the same measure, so the English pages
   get a little more leading rather than a different width. */
html[lang="en"] body { line-height: 1.65; }

/* ---- links ---------------------------------------------------------------
 * Underlined, not colour-only: colour alone fails for anyone who cannot see
 * it. Visited is a separate hue rather than a dimmer one, because a dimmer
 * visited link reads as disabled. Both clear 7:1 on white.
 */

a {
  color: var(--act);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
a:visited { color: var(--visited); }
a:hover { color: var(--act-hover); text-decoration-thickness: 2px; }
a:visited:hover { color: #513369; }

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

/* ---- header --------------------------------------------------------------
 * One line deep. The wordmark, where you are, and the language. Navigation is
 * chrome rather than content, so it is ink and grey with no underline: it
 * would otherwise be the loudest thing on every page.
 */

header {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 14px;
  padding: 20px 32px;
  border-bottom: 1px solid var(--rule);
}

h1 { font-size: 17px; font-weight: 600; margin: 0; letter-spacing: -0.005em; }
.sub { color: var(--muted); font-size: 13px; }

a.home { text-decoration: none; color: inherit; }
a.home h1 { display: inline; }
a.home:hover h1 { color: var(--act); }

header nav { display: flex; align-items: baseline; gap: 22px; margin-left: 24px; }
header nav a {
  color: var(--muted);
  text-decoration: none;
  font-size: 15px;
  white-space: nowrap;
}
header nav a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
header nav a.here { color: var(--ink); font-weight: 600; }

/* A setting, not a destination, so it sits at the end and looks like a
   control rather than a link. */
.lang {
  margin-left: auto;
  font: inherit;
  font-size: 13px;
  padding: 3px 12px;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--page);
  color: var(--muted);
  cursor: pointer;
  text-decoration: none;
}
.lang:hover { color: var(--act); border-color: var(--act); background: var(--page); }

/* ---- page ---------------------------------------------------------------- */

/* One column, every page. Two widths meant the header and footer stayed put
   while the content under them jumped 14rem sideways on the way from /data/
   to anywhere else -- the kind of shift that reads as a different site rather
   than a wider page.
   52rem is chosen from the content: the coverage table on /data/ wants 747px
   and the parquet path below it overflows anything narrower, while prose is
   capped at its own measure, so the rest of the page is margin. Wider than
   this and every prose page becomes a short column against a long emptiness. */
main {
  max-width: var(--wide);
  margin: 0 auto;
  padding: 40px 32px 72px;
}

/* Prose holds its measure; tables and the calendar are free to be wider. */
p, li, dd, .lede p { max-width: var(--measure); }

h2 { font-size: 20px; font-weight: 600; margin: 0 0 12px; letter-spacing: -0.01em; }
h3 { font-size: 16px; font-weight: 600; margin: 28px 0 6px; }

.lede h2 { font-size: 27px; line-height: 1.35; margin-bottom: 14px; }
/* The opening paragraph only, and only when it has not asked for something
   else. `.lede p` caught every paragraph in the block, so a line marked
   `muted small` came out at 17px in body ink -- a note written to be quiet,
   rendered as the loudest thing under the title. */
.lede > p:first-of-type:not(.small) { color: var(--ink-2); font-size: 17px; }

p { margin: 0 0 14px; }
ul, ol { margin: 10px 0 16px; padding-left: 22px; }
li { margin-bottom: 6px; }

.muted { color: var(--muted); }
.small { font-size: 14px; }
.hint { color: var(--muted); font-size: 13px; margin: 6px 0 0; }
.label { font-size: 13px; color: var(--muted); }

/* ---- sections ------------------------------------------------------------
 * Reading pages are not boxed. Nine identical rounded rectangles said the same
 * thing about nine different kinds of content, which is to say nothing. Space
 * separates them, and one hairline marks the join.
 */

.card { margin: 0 0 8px; }
.card + .card { border-top: 1px solid var(--rule); margin-top: 44px; padding-top: 40px; }

.card h3:first-of-type { margin-top: 18px; }

/* ---- panels: the surfaces you operate ------------------------------------
 * The download page is a tool rather than a document, so its working surfaces
 * are panels. A panel says this is a thing you use; prose does not need one.
 */

#login,
#app > .card,
.steps > .card {
  background: var(--sunken);
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 24px;
  margin: 0 0 20px;
}
#login, #app > .card + .card, .steps > .card { border-top: 1px solid var(--rule); padding-top: 24px; margin-top: 0; }
/* Signed out there is no calendar yet, so the panel is the width of the form
   in it rather than the width of what will replace it. */
#login { max-width: 34rem; }
#login h2 { margin-bottom: 10px; }

/* The break between reading and doing. A hairline rather than a heavier rule:
   it separates two parts of one page, not two pages.
   Full column width, like the border a `.card + .card` draws: it divides the
   page rather than the prose, and cut to the text measure it read as a short
   line floating above the form instead of a rule under everything above it. */
.sep {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 40px 0 32px;
}
#app > .card + .card { margin-top: 20px; }

/* ---- buttons -------------------------------------------------------------
 * Two weights, and the difference carries meaning rather than taste.
 *
 *   Filled indigo  — commits something: signing in starts the download period,
 *                    unlocking spends market-days. Neither can be undone.
 *   Outlined       — free and repeatable: downloading a file you already
 *                    unlocked costs nothing and may be done again.
 *
 * A buyer should be able to tell those apart without reading, which is why the
 * spending action is the only filled control on the page.
 */

button, .cta {
  display: inline-block;
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  line-height: 1.4;
  padding: 9px 18px;
  border: 1px solid var(--act);
  border-radius: 6px;
  background: var(--act);
  color: #fff;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
button:hover, .cta:hover { background: var(--act-hover); border-color: var(--act-hover); color: #fff; }
.cta:visited { color: #fff; }

button:disabled {
  background: var(--sunken);
  border-color: var(--rule-strong);
  color: var(--muted);
  cursor: default;
}
button:disabled:hover { background: var(--sunken); border-color: var(--rule-strong); color: var(--muted); }

/* Outlined: the free, repeatable half of the pair. */
.cta.ghost, button.secondary, #tokenIssue button, .file {
  background: var(--page);
  color: var(--act);
  border: 1px solid var(--act);
}
.cta.ghost:hover, button.secondary:hover, #tokenIssue button:hover:not(:disabled), .file:hover {
  background: var(--act-soft);
  color: var(--act-hover);
  border-color: var(--act-hover);
}
.cta.ghost:visited { color: var(--act); }

button.warn { background: var(--page); color: var(--warn); border-color: var(--warn); }
button.warn:hover { background: #fdf7ec; color: var(--warn); border-color: var(--warn); }
button.danger { background: var(--page); color: var(--bad); border-color: var(--bad); }
button.danger:hover { background: #fdf2f2; color: var(--bad); border-color: var(--bad); }

/* ---- forms --------------------------------------------------------------- */

label { display: block; margin-bottom: 14px; font-size: 14px; color: var(--muted); }
input, select {
  display: block;
  width: 100%;
  margin-top: 5px;
  padding: 10px 12px;
  border: 1px solid var(--rule-strong);
  border-radius: 6px;
  background: var(--page);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
}
input:focus, select:focus { border-color: var(--act); }
/* A placeholder here shows the format of an order number, so it has to be
   legible: 4.5:1 rather than the usual near-invisible grey. */
input::placeholder { color: #6f7885; }

/* A field is as wide as what goes in it. An order number stretched across a
   960-pixel panel is harder to read back than one that is not. */
#login label, #login input { max-width: 22rem; }
#login .small { max-width: var(--measure); }

.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 0 20px; }
.row { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.row select { max-width: 22rem; }

/* ---- code ---------------------------------------------------------------- */

code { font-family: var(--mono); font-size: .9em; }
pre {
  background: var(--sunken);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 14px 16px;
  overflow-x: auto;
  font-size: 13.5px;
  line-height: 1.7;
  margin: 14px 0;
  max-width: var(--wide);
}
pre code { font-size: inherit; }

/* ---- tables --------------------------------------------------------------
 * Ruled rows, no fill. Figures align because the data is meant to be compared
 * down a column.
 */

table { width: 100%; border-collapse: collapse; margin: 14px 0; font-size: 14.5px; }
th, td { text-align: left; padding: 9px 10px 9px 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
th { color: var(--muted); font-weight: 600; font-size: 13px; }
td { font-variant-numeric: tabular-nums; }

table.schema {
  width: auto;
  border-collapse: collapse;
  margin: 12px 40px 20px 0;
  display: inline-table;
  vertical-align: top;
  font-size: 14px;
}
table.schema th { padding: 6px 18px 7px 0; border-bottom: 1px solid var(--rule-strong); color: var(--ink); }
table.schema td { padding: 6px 18px 6px 0; border-bottom: 1px solid var(--rule); color: var(--ink-2); }

/* ---- the notice ----------------------------------------------------------
 * `doc/03_legal-compliance-note.md` section 6 wants it before the decision,
 * not only in the footer. It is set apart without being alarming: a disclaimer
 * in warning colours reads as a system error rather than as terms.
 */

.notice {
  border-left: 3px solid var(--rule-strong);
  background: var(--sunken);
  border-radius: 0 6px 6px 0;
  padding: 14px 18px;
  margin: 20px 0 8px;
  color: var(--ink-2);
  font-size: 15px;
  max-width: var(--measure);
}
/* A notice that runs to more than one paragraph, which the entrance's does:
   the two deadlines are one thought and what a download settles is
   another, and run together they read as a wall. */
.notice p { margin: 0 0 10px; }
.notice p:last-child { margin-bottom: 0; }

/* ---- published articles --------------------------------------------------
 * A preview and a way out, not a page pretending to hold the article. The
 * badge says where it lives and the link leaves; both are the design rather
 * than decoration, per `08_article-feed-aggregator.md` section 7.
 */

.entry { padding: 20px 0; border-bottom: 1px solid var(--rule); max-width: var(--measure); }
.entry:first-child { padding-top: 4px; }
.entry:last-child { border-bottom: none; padding-bottom: 4px; }
.entry h3 { margin: 0 0 6px; font-size: 17px; line-height: 1.45; }
.entry h3 a { text-decoration: none; }
.entry h3 a:hover { text-decoration: underline; text-underline-offset: 3px; }
.entry-meta { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; }

.badge {
  font-size: 12px;
  padding: 2px 9px;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  color: var(--muted);
  white-space: nowrap;
}

/* Two lines, then stop. A snippet is there to help someone decide, and a feed
   hands over as much of the article as it feels like. */
.clamp {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin: 0;
}

/* ---- home page list ------------------------------------------------------ */

.points { margin: 0; }
.points dt { font-weight: 600; margin-top: 24px; }
.points dd { margin: 4px 0 0; color: var(--ink-2); }

/* ---- figures -------------------------------------------------------------
 * The archive's own numbers. Tabular so the digits line up, and sized to be
 * read rather than admired.
 */

.figures { display: flex; gap: 2.5rem; flex-wrap: wrap; margin: .5rem 0 .25rem; }
.figures div { display: flex; flex-direction: column; }
.big { font-size: 1.9rem; font-weight: 600; line-height: 1.2; font-variant-numeric: tabular-nums; }

/* ---- status --------------------------------------------------------------- */

.err, .error { color: var(--bad); margin-top: 10px; }
.ok-msg { color: var(--good); margin-top: 10px; }

.pill { margin-left: auto; font-size: 12px; padding: 3px 11px; border-radius: 999px;
        border: 1px solid var(--rule-strong); color: var(--muted); }
.pill.ok { color: var(--good); border-color: var(--good); }
.pill.bad { color: var(--bad); border-color: var(--bad); }

/* Tabs pick a view; they do not commit anything, so they are not painted like
   the buttons that do. Quiet until chosen, and the chosen one is tinted rather
   than filled -- a filled tab would outrank the actions inside its own panel. */
.tabs { display: flex; gap: 8px; margin-bottom: 18px; flex-wrap: wrap; }
.tab {
  background: var(--page);
  border-color: var(--rule-strong);
  color: var(--ink-2);
  font-weight: 500;
}
.tab:hover { background: var(--sunken); border-color: var(--act); color: var(--act); }
.tab.active, .tab.active:hover {
  background: var(--act-soft); border-color: var(--act); color: var(--act); font-weight: 600;
}

.token-box { background: var(--page); border: 1px solid var(--act); border-radius: 8px;
             padding: 16px; margin-top: 16px; }
.token-box code { font-size: 14px; word-break: break-all; display: block; margin: 8px 0; }

/* ---- the banner ----------------------------------------------------------
 * Read once, at the top of the entrance, and never operated. So it is not a
 * panel: panels are surfaces you use, and treating this as one would have said
 * there was something here to do. Ink on the left edge rather than indigo,
 * because indigo is reserved for things that can be acted on.
 */

.banner {
  background: var(--sunken);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--ink);
  border-radius: 0 8px 8px 0;
  padding: 18px 22px;
  margin: 0 0 20px;
}
.banner p { margin: 0 0 10px; }
.banner p:last-child { margin-bottom: 0; }
.banner-title { font-weight: 600; font-size: 16.5px; }

/* ---- the Komachi quick start --------------------------------------------- */

#komachi pre { margin: 14px 0; }

#tokenIssue { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
#tokenIssue button:disabled { opacity: .55; cursor: default; background: var(--page); }

/* A token is fifty-odd characters and a phone is not. It wraps rather than
   scrolling sideways, because a token scrolled half out of view is one a buyer
   copies half of. */
#tokenHint.revealed { font-weight: 600; word-break: break-all;
                      white-space: pre-wrap; user-select: all; }

/* ---- the two steps -------------------------------------------------------- */

.card.step h2 { display: flex; align-items: center; gap: 10px; }
.stepno {
  display: inline-grid; place-items: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--ink); color: var(--page);
  font-size: 13px; font-weight: 600; flex: none;
}

.steps { display: grid; grid-template-columns: minmax(0, 1fr) 20rem; gap: 20px; align-items: start; }
.steps > .card { margin: 0; }
#filesCard { position: sticky; top: 20px; max-height: calc(100vh - 40px); overflow-y: auto; }

/* ---- the calendar --------------------------------------------------------
 * The archive made visible, and the one place this design spends any weight.
 *
 * A day you own is filled in the same indigo as a button, because owning it is
 * what the buttons were for: the calendar reads as the record of what the
 * primary action has already done. The three live states are told apart by how
 * much of that indigo each carries -- an outline on hover, a tint once picked,
 * the full fill once it is yours -- so hovering a day never looks like owning
 * one. A day that was never published is drawn as an absence rather than as an
 * error, because it is not one.
 */

.legend { font-size: 14px; color: var(--muted); margin-bottom: 12px; }
.sw { display: inline-block; width: .85rem; height: .85rem; border-radius: 3px;
      vertical-align: -1px; margin: 0 .25rem 0 1rem; border: 1px solid var(--rule-strong); }
.sw:first-child { margin-left: 0; }
.sw.owned { background: var(--act); border-color: var(--act); }
.sw.avail { background: var(--page); }
.sw.none { background: var(--sunken); border-style: dashed; }

.calendar { margin-bottom: 18px; }
.cal-year { font-size: 15px; font-weight: 600; margin: 24px 0 10px; padding-bottom: 5px;
            border-bottom: 1px solid var(--rule); }
.cal-year:first-child { margin-top: 0; }
/* The month names itself once, above its own days. Quiet, because the cells
   are the thing being read and the label is only there to place them. */
.cal-month { margin-bottom: 20px; }
.cal-month-label { font-size: 13px; color: var(--muted); margin: 0 0 6px;
                   font-variant-numeric: tabular-nums; }
.cal-days { display: grid; grid-template-columns: repeat(14, minmax(0, 1fr)); gap: 4px; }

/* width:100% because a button does not stretch to its grid track the way a div
   does: left to itself it shrink-wraps, and MM-DD then wraps onto two lines. */
.day {
  font: inherit; font-size: 13px; font-weight: 400;
  padding: 8px 0;
  border: 1px solid var(--rule-strong);
  border-radius: 4px;
  background: var(--page);
  color: var(--ink);
  cursor: pointer;
  text-align: center;
  font-variant-numeric: tabular-nums;
  width: 100%; white-space: nowrap;
  transition: none;
}
.day.none { background: var(--sunken); border-style: dashed; border-color: var(--rule);
            color: #6b7381; cursor: default; }
.day.owned { background: var(--act); border-color: var(--act); color: #fff; }
.day.avail:hover { border-color: var(--act); background: var(--page); color: var(--act); }
/* Also while hovered: `.day.avail:hover` is one class heavier than `.day.picked`
   on its own, so a day you had chosen turned back into an unchosen one for as
   long as the cursor sat on it -- exactly when you are looking at it. */
.day.picked, .day.avail.picked:hover {
  background: var(--act-soft); border-color: var(--act); color: var(--act);
  font-weight: 600; }

.unlock { display: flex; gap: .9rem; align-items: center; flex-wrap: wrap; margin-top: 4px; }

/* ---- the file list -------------------------------------------------------- */

.file { font: inherit; font-size: 13.5px; margin-right: .5rem; padding: .4rem .9rem;
        border-radius: 5px; cursor: pointer; }
.filerow { display: flex; align-items: center; gap: 12px; padding: 9px 0;
           border-bottom: 1px solid var(--rule); flex-wrap: wrap; }
.filerow:last-child { border-bottom: none; }
.filerow.closed .filedate { color: var(--muted); }
.filedate { width: 6.5rem; flex: none; font-variant-numeric: tabular-nums; font-size: 14px; }
.filebtns { display: flex; gap: 8px; }
.filebtns .file { margin: 0; }

/* Bulk sits above the per-day rows: it is the shortcut, not the default. */
.downloadall { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
               padding-bottom: 12px; margin-bottom: 6px; border-bottom: 1px solid var(--rule); }
/* "Both" carries no styling of its own. It fetches the same files the two
   buttons beside it fetch, at the same cost, so weighting it differently said
   there was a difference to notice. `.both` still exists for the click
   handler, which does need to tell them apart. */

/* The download column is narrow, so a row wraps rather than being squeezed. */
#filesCard .filerow { gap: 6px 10px; }
#filesCard .filedate { width: 100%; font-size: 13px; color: var(--muted); }
#filesCard .file { padding: 5px 11px; font-size: 13px; }

/* Narrower cells, since the calendar no longer has the page to itself. Placed
   before the width rules so those can override it. */
/* Fourteen to a row is two weeks, and the product is sold in whole weeks, so
   a row is a unit a buyer already thinks in. It stays fourteen inside the
   narrower step panel rather than dropping to ten. */
/* Two columns of page means half of it for the calendar, and fourteen days
   across that is a 23px cell for a five-character date. Seven is what the
   archive is sold in, so a row is a week either way. */
.steps .cal-days { grid-template-columns: repeat(7, minmax(0, 1fr)); }
.steps .day { font-size: 12.5px; padding: 8px 0; }

/* ---- footer --------------------------------------------------------------
 * Footer links are links: the same indigo, the same visited violet. They were
 * grey, which made a visited one indistinguishable from an unvisited one and
 * from the text around it.
 */

footer {
  padding: 24px 32px 36px;
  border-top: 1px solid var(--rule);
  margin-top: 56px;
  display: flex;
  gap: 8px 26px;
  flex-wrap: wrap;
  align-items: baseline;
  color: var(--muted);
  font-size: 13.5px;
}
footer a { color: var(--act); }
footer a:visited { color: var(--visited); }
footer p, footer span { max-width: none; margin: 0; }

/* ---- responsive ----------------------------------------------------------- */

/* One column below the width where the calendar stops fitting beside a list. */
@media (max-width: 68rem) {
  .steps { grid-template-columns: minmax(0, 1fr); }
  #filesCard { position: static; max-height: none; }
  /* Stacked, the calendar has the whole column back, so a fortnight fits
     across it again. */
  .steps .cal-days { grid-template-columns: repeat(14, minmax(0, 1fr)); }
}

@media (max-width: 44rem) {
  header { padding: 16px 20px; gap: 10px; }
  header nav { margin-left: 0; gap: 18px; }
  main, #auth { padding: 28px 20px 56px; }
  footer { padding: 20px 20px 32px; }
  .lede h2 { font-size: 23px; }
  table.schema { margin-right: 0; display: table; width: 100%; }

  /* Width rules last, so they win on source order against the .steps
     overrides above rather than depending on selector weight. Equal
     specificity is decided by position, which is why an earlier media query
     here did nothing at all. */
  .steps .cal-days, .cal-days { grid-template-columns: repeat(7, minmax(0, 1fr)); }
  /* A finger needs a bigger target than a cursor, and halving the columns
     leaves the height to spare. */
  .steps .day, .day { font-size: 12px; padding: 12px 0; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
