/* Jade Tile Mahjong Club — foundations.
   Palette and type used by every page. The board and the exec console add
   their own sheet on top; nothing here knows about either.

   The look is a mahjong table seen from above: rice paper under a jade felt
   panel, ivory tiles on it, one cinnabar accent for the things that matter.
   Everything is drawn with borders and flat fills — no emoji, no gradients
   doing work that a solid colour does better. */

:root {
  /* paper */
  --paper: #f6f1e6;
  --paper-2: #fbf8f1;
  --paper-edge: #e3d9c4;

  /* ink */
  --ink: #17231f;
  --ink-2: #41524b;
  --ink-3: #74837c;

  /* jade felt */
  --felt: #12362e;
  --felt-2: #0b2721;
  --felt-edge: #1f4c41;
  --felt-ink: #d8e6de;
  --felt-ink-2: #8fae9f;

  --bamboo: #2f7f5b;
  --cinnabar: #b3392a;
  --gold: #a8842c;

  /* tile faces */
  --tile: #fbf7ec;
  --tile-edge: #ded3ba;
  --tile-base: #c9bc9d;

  /* the table's wooden rim */
  --wood: #5e3b22;
  --wood-2: #3c2514;

  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .42 0 0 0 0 .34 0 0 0 0 .2 0 0 0 .07 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  --felt-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.3' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .8 0 0 0 0 1 0 0 0 0 .9 0 0 0 .09 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23f)'/%3E%3C/svg%3E");
  --fret: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='12' viewBox='0 0 24 12'%3E%3Cpath d='M0 11H12V1H3V8H9V4H6' fill='none' stroke='%23cdbf9f' stroke-width='1.4'/%3E%3Cpath d='M12 11H24' fill='none' stroke='%23cdbf9f' stroke-width='1.4'/%3E%3C/svg%3E");

  --radius: 10px;
  --radius-lg: 16px;
  --shell: 640px;

  --serif: "Kaisei Decol", "Iowan Old Style", Georgia, serif;
  --sans: "Zen Kaku Gothic New", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;
  /* Scores and totals. Lining, equal-width figures so a column of points
     lines up — without reaching for a monospace face that reads as code. */
  --num: "Zen Kaku Gothic New", system-ui, -apple-system, "Segoe UI", sans-serif;
}

.num { font-family: var(--num); font-variant-numeric: tabular-nums lining-nums; }

* { box-sizing: border-box; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

body {
  margin: 0;
  background-color: var(--paper);
  background-image: var(--grain);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16.5px;
  line-height: 1.6;
}

.shell { max-width: var(--shell); margin: 0 auto; padding: 0 20px; }
.shell-wide { max-width: 1040px; margin: 0 auto; padding: 0 20px; }

h1, h2, h3 { font-family: var(--serif); font-weight: 400; letter-spacing: -0.01em; }

a { color: var(--bamboo); text-underline-offset: 3px; }
a:hover { color: var(--felt); }

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

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- masthead ---------- */

.masthead {
  position: relative;
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 26px 0 30px;
  margin-bottom: 8px;
}
.masthead::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 12px;
  background: var(--fret) repeat-x;
  background-size: 24px 12px;
}
/* The club's seal, top left of every page and again in the footer. */
.masthead .logo { flex: none; display: block; line-height: 0; }
.masthead .logo img { height: 64px; width: auto; display: block; }
.masthead h1.logo-title { margin: 0; line-height: 0; }
.site-foot .foot-profile { text-decoration: none; color: var(--ink-2); }
.masthead h1 { font-size: 22px; line-height: 1.15; margin: 0; }
.masthead p { margin: 1px 0 0; font-size: 13.5px; color: var(--ink-3); font-style: italic; }
.masthead .spacer { flex: 1; }
.masthead .exec-link {
  font-size: 13.5px; color: var(--ink-2); text-decoration: none;
  background: var(--tile);
  border: 1px solid var(--tile-edge);
  border-radius: 6px 6px 5px 5px;
  box-shadow: 0 2px 0 var(--tile-base);
  padding: 5px 12px;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.masthead .exec-link:hover { color: var(--ink); transform: translateY(-1px); box-shadow: 0 3px 0 var(--tile-base); }
.masthead .exec-link:active { transform: translateY(1px); box-shadow: 0 1px 0 var(--tile-base); }
.masthead .exec-dash { background: var(--cinnabar); border-color: var(--cinnabar); color: #fff8ec; box-shadow: 0 2px 0 #7d2419; }
.masthead .exec-dash:hover { color: #fff; box-shadow: 0 3px 0 #7d2419; }
.masthead .account-link { background: linear-gradient(var(--felt-edge), var(--felt) 45%); border-color: var(--felt-2); color: #f3efe2; box-shadow: 0 2px 0 var(--felt-2); font-weight: 500; }
.masthead .account-link:hover { color: #fff; box-shadow: 0 3px 0 var(--felt-2); }

/* ---------- hero ---------- */

.hero { padding: 6px 0 22px; }
.hero h2 { font-size: clamp(30px, 7.5vw, 44px); line-height: 1.05; letter-spacing: -0.02em; margin: 0 0 10px; }
.hero p { margin: 0; max-width: 48ch; color: var(--ink-2); font-size: 15.5px; }
.hero .updated { margin-top: 12px; font-size: 13.5px; color: var(--ink-3); }
.hero .updated b { font-weight: 500; color: var(--ink-2); }
/* The monthly prizes: the one line on the welcome that should not be missed. */
.hero .prize-note {
  display: flex; gap: 12px; align-items: flex-start;
  max-width: 52ch; margin-top: 14px; padding: 12px 14px;
  background: var(--paper-2); border: 1px solid var(--paper-edge); border-left: 3px solid var(--cinnabar); border-radius: 10px;
  font-size: 15px; color: var(--ink-2);
}
.hero .prize-note .seal { flex: none; margin-top: 1px; }
.hero .prize-note b { color: var(--ink); font-weight: 600; }
.board-switch { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
/* Wide screens: the leaderboard switch sits to the right of the intro instead
   of under it, so the top of the page is not all on the left. */
@media (min-width: 980px) {
  .hero:has(.board-switch) { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 32px; }
  .hero:has(.board-switch) > :not(.board-switch) { grid-column: 1; }
  .hero .board-switch { grid-column: 2; grid-row: 1 / span 3; align-self: end; margin: 0 0 4px; }
}
@media (max-width: 520px) {
  /* Two equal halves on a phone, lined up with the board tabs below. */
  .board-switch { display: grid; grid-template-columns: 1fr 1fr; }
  .board-switch .btn { text-align: center; padding-left: 8px; padding-right: 8px; }
}


/* A club night's results: one table, both boards. */
.results { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.results th { text-align: left; font-size: 12.5px; font-weight: 500; color: var(--ink-3); padding: 0 8px 8px; }
.results td { padding: 10px 8px; border-top: 1px solid var(--paper-edge); }
.results .num { text-align: right; }
.results .rank { width: 2.5em; color: var(--ink-3); }
.results .board { font-size: 12.5px; color: var(--ink-3); }
.night-pick { margin: 0 0 16px; }

/* ---------- buttons ---------- */

/* The main action is the back of a tile — jade, with its thickness under it —
   and everything quieter is the ivory face. Pressing one sets it down. */
.btn {
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  border: 1px solid var(--felt-2);
  background: linear-gradient(var(--felt-edge), var(--felt) 45%);
  color: #f3efe2;
  border-radius: 7px 7px 6px 6px;
  box-shadow: 0 3px 0 var(--felt-2), 0 5px 10px rgb(11 39 33 / 0.18);
  padding: 10px 18px 9px;
  cursor: pointer;
  transition: transform 0.12s ease, box-shadow 0.12s ease, filter 0.12s ease;
}
.btn:hover { filter: brightness(1.08); transform: translateY(-1px); box-shadow: 0 4px 0 var(--felt-2), 0 7px 14px rgb(11 39 33 / 0.2); }
.btn:active { transform: translateY(2px); box-shadow: 0 1px 0 var(--felt-2); }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; transform: none; filter: none; }
.btn-quiet {
  background: var(--tile); color: var(--ink-2);
  border-color: var(--tile-edge);
  box-shadow: 0 3px 0 var(--tile-base), 0 4px 8px rgb(62 38 20 / 0.08);
}
.btn-quiet:hover { color: var(--ink); box-shadow: 0 4px 0 var(--tile-base), 0 6px 12px rgb(62 38 20 / 0.1); }
.btn-quiet:active { box-shadow: 0 1px 0 var(--tile-base); }
.btn-danger {
  background: var(--tile); color: var(--cinnabar);
  border-color: #e3c7bf;
  box-shadow: 0 3px 0 #d9b2a8;
}
.btn-danger:hover { background: #fdf3ef; box-shadow: 0 4px 0 #d9b2a8; }
.btn-danger:active { box-shadow: 0 1px 0 #d9b2a8; }
.btn-sm { padding: 6px 12px 5px; font-size: 13.5px; }

/* A cinnabar seal stamped beside a heading, the way a scroll is signed. */
.sealed { display: flex; align-items: center; gap: 0.5em; }
.seal {
  display: inline-grid; place-items: center; flex: none;
  width: 1.6em; height: 1.6em;
  background: var(--cinnabar);
  color: #fff3ea;
  font-family: var(--serif);
  font-size: 0.8em;
  line-height: 1;
  border-radius: 3px;
  box-shadow: inset 0 0 0 2px rgb(255 255 255 / 0.2);
  transform: rotate(-4deg);
}

/* The demo site's banner (assets/demo.js). */
.demo-bar {
  position: sticky; top: 0; z-index: 40;
  padding: 7px 16px;
  text-align: center; font-size: 13px;
  color: var(--felt-ink); background: var(--felt);
}
a.btn { display: inline-block; text-align: center; text-decoration: none; }
.link-btn {
  font: inherit; color: var(--ink-2);
  background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.link-btn:hover { color: var(--ink); }

/* ---------- fields ---------- */

.field { display: block; margin: 0 0 14px; }
.field > span {
  display: block; font-size: 14px; font-weight: 500; color: var(--ink-2); margin-bottom: 5px;
}
.field input, .field select, .field textarea, .input {
  font: inherit; font-size: 15.5px; width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--paper-edge);
  border-radius: var(--radius);
  background: var(--paper-2);
  color: var(--ink);
}
.field input:focus, .field select:focus, .input:focus { border-color: var(--bamboo); }

/* ---------- notes, footer ---------- */

.note { margin: 0; color: var(--ink-3); font-size: 14px; max-width: 54ch; }

.site-foot {
  position: relative;
  margin-top: 36px;
  padding: 30px 0 46px;
  font-size: 13.5px;
  color: var(--ink-3);
  display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap;
}
.site-foot a { color: var(--ink-3); }
.site-foot::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0;
  height: 12px;
  background: var(--fret) repeat-x;
  background-size: 24px 12px;
}


/* ---------- felt panel ----------
   The dark jade surface both the public board and the exec preview sit on. */

.felt {
  background-color: var(--felt);
  background-image: radial-gradient(130% 90% at 50% 0%, rgb(255 255 255 / 0.07), transparent 62%), var(--felt-grain);
  border-radius: 12px;
  padding: 20px 18px 22px;
  margin: 7px;
  color: var(--felt-ink);
  box-shadow:
    inset 0 2px 10px rgb(0 0 0 / 0.35),
    0 0 0 6px var(--wood),
    0 0 0 7px var(--wood-2),
    0 16px 32px rgb(62 38 20 / 0.28);
}
.felt-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 14px;
}
.felt-head h3 { margin: 0; font-size: 17px; color: #fff; letter-spacing: 0.02em; }
.felt-head span { font-size: 12.5px; color: var(--felt-ink-2); }

/* ---------- tiles ----------
   The ivory body. What is printed on it is drawn by tileart.js as an SVG that
   fills the face, so this only ever styles the tile itself. */

.tile {
  position: relative;
  display: inline-block;
  width: 40px; height: 54px;
  flex: none;
  background: var(--tile);
  border: 1px solid var(--tile-edge);
  border-radius: 6px 6px 4px 4px;
  box-shadow: 0 2px 0 var(--tile-base);
  line-height: 0;
  user-select: none;
  overflow: hidden;
}
.tile-face { display: block; width: 100%; height: 100%; }
.tile.win { box-shadow: 0 0 0 2px var(--cinnabar), 0 2px 0 var(--tile-base); }

.tile-sm { width: 28px; height: 38px; border-radius: 5px 5px 3px 3px; }
.tile-lg { width: 52px; height: 70px; border-radius: 7px 7px 5px 5px; }
/* ---------- scroll ----------
   Native CSS scroll-driven animations: no library, no scroll listener, and the
   compositor runs them off the main thread. Browsers without them get the page
   with everything already in place — scroll.js only adds the .seen class those
   browsers need, and does nothing where the timelines work. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal {
      animation: reveal linear both;
      animation-timeline: view();
      /* Finishes while the element is still entering, so anything already on
         screen — or on a page too short to scroll — is fully drawn, not stuck
         half-faded at the bottom of the first view. */
      animation-range: entry 0% entry 60%;
    }
    /* A thread of jade across the top, as long as the page is scrolled. */
    .scroll-thread {
      position: fixed; inset: 0 0 auto; height: 2px; z-index: 30;
      transform-origin: 0 50%;
      background: linear-gradient(90deg, var(--bamboo), var(--felt));
      animation: thread linear both;
      animation-timeline: scroll(root block);
    }
    /* The rule between sections draws itself as it comes up. */
    .draw path, .draw line, .draw circle {
      animation: draw linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 90%;
    }
  }
}

@keyframes reveal {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: none; }
}
@keyframes thread { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes draw { from { stroke-dashoffset: var(--len, 300); } to { stroke-dashoffset: 0; } }

/* The fallback path, and what everyone sees with reduced motion on. */
@media (prefers-reduced-motion: no-preference) {
  .js-reveal .reveal:not(.seen) { opacity: 0; transform: translateY(18px); }
  .js-reveal .reveal { transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1); }
}

/* ---------- the drawn divider ---------- */

.divider {
  position: relative;
  display: grid; place-items: center;
  height: 44px;
  margin: 10px 0;
}
.divider::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 50%;
  border-top: 1px solid var(--paper-edge);
}
.divider-mark {
  position: relative;
  width: 64px; height: 44px;
  background: var(--paper);
  padding: 0 6px;
}
.divider-mark [stroke] { stroke-linecap: round; stroke-linejoin: round; fill: none; }

/* The masthead sits above a narrow phone: the subtitle and the link both have
   to stay on one line rather than stacking into the tiles below. */
@media (max-width: 420px) {
  .masthead { gap: 10px; padding: 20px 0 16px; }
  .masthead h1 { font-size: 19px; }
  .masthead .logo img { height: 50px; }
  .masthead p { font-size: 11.5px; letter-spacing: 0.05em; }
  .masthead .exec-link { padding: 4px 10px; font-size: 12.5px; white-space: nowrap; }
  .masthead { flex-wrap: wrap; row-gap: 12px; }
  .masthead .spacer { flex-basis: 100%; height: 0; }
  .masthead .exec-link { flex: 1; text-align: center; padding: 8px 10px; font-size: 13.5px; }
}

/* You are at a table: a reminder pinned to the bottom of every page. */
.my-table {
  position: fixed; left: 50%; bottom: calc(14px + env(safe-area-inset-bottom)); z-index: 30;
  transform: translateX(-50%);
  display: flex; align-items: center; gap: 10px;
  max-width: calc(100vw - 28px);
  padding: 10px 16px; border-radius: 999px;
  background: linear-gradient(var(--felt-edge), var(--felt) 45%);
  border: 1px solid var(--felt-2);
  box-shadow: 0 3px 0 var(--felt-2), 0 10px 24px rgb(11 39 33 / 0.3);
  color: #f3efe2; font-size: 14px; text-decoration: none; white-space: nowrap;
}
.my-table span:nth-child(2) { overflow: hidden; text-overflow: ellipsis; }
.my-table b { font-weight: 500; color: #fff; padding-left: 10px; border-left: 1px solid rgb(243 239 226 / 0.3); }
.my-table:hover { color: #fff; }
.my-table-dot { width: 8px; height: 8px; flex: none; border-radius: 50%; background: #5fd08f; box-shadow: 0 0 0 4px rgb(95 208 143 / 0.2); }
body.has-my-table { padding-bottom: 76px; }

/* Plain reading pages: privacy and terms, not found. */
.prose { max-width: 640px; margin: 8px auto 0; font-size: 15.5px; line-height: 1.65; color: var(--ink-2); }
.prose h2 { margin: 30px 0 8px; font-size: 21px; color: var(--ink); }
.prose ul { padding-left: 20px; }
.prose li { margin: 6px 0; }
.prose code { font-family: var(--mono); font-size: 13.5px; background: var(--paper-2); padding: 1px 5px; border-radius: 4px; }
.prose-date { font-size: 13px; color: var(--ink-3); }
.prose-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 20px; }
