/* LOREHOUSE · design tokens
   The single source of truth for colour, type, spacing and radius.
   Linked by index.html, landing.html and login.html — nothing else declares a raw
   hex, a raw font-size, an off-grid space, or an ad-hoc radius.

   Colour comes in three generated palettes × light/dark (the block at the end of
   this file). Contrast for every text and control pair is measured by
   docs/design/handoff-satu-lorehouse/palette.py, not annotated here. */

/* ---------- typeface ----------
   Two voices, two families:

     Plus Jakarta Sans  the reading voice — headings, body, rendered documents, and
                        the "Lorehouse" wordmark (--font-logo)
     Geist              the interface voice — labels, controls, counts, metadata, the
                        uppercase micro-labels that used to run in Geist Mono, and code

   Both are SIL OFL 1.1, so both are self-hosted from /fonts and travel with the repo.
   Plus Jakarta Sans is one variable file (latin subset, weights 200-800, ~27 KB), so
   there is no third-party font request on any page. Satoshi, which this replaced,
   needed the Fontshare CDN. The logo rules live in public/brand/kit/README.md. */
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/Geist/Geist-400.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/Geist/Geist-500.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/Geist/Geist-600.woff2") format("woff2");
}
@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/Geist/Geist-700.woff2") format("woff2");
}
@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("fonts/PlusJakartaSans/PlusJakartaSans-variable.woff2") format("woff2");
}
:root {
  /* ---------- colour ----------
     Every colour role (--bg … --shadow-lg) is declared per palette in the generated
     block at the end of this file. What stays here is built from those roles. */

  /* Glow is a state, not a texture. Reserved for the focused / active element:
     the primary button, the open palette, an active drop target.
     A custom property that reads var() resolves where it is declared, so these three
     are declared again on .art-zone below — otherwise a button inside a hero would
     glow in the page's accent instead of the zone's. */
  --glow: 0 0 0 1px color-mix(in srgb, var(--accent) 25%, transparent),
    0 2px 10px color-mix(in srgb, var(--accent) 14%, transparent),
    0 8px 32px color-mix(in srgb, var(--accent) 12%, transparent);
  --glow-soft: 0 2px 12px color-mix(in srgb, var(--accent) 10%, transparent),
    0 10px 36px color-mix(in srgb, var(--accent) 9%, transparent);
  --ambient: radial-gradient(
    90rem 44rem at 50% -16rem,
    color-mix(in srgb, var(--accent) 8%, transparent),
    transparent 65%
  );

  /* ---------- type ----------
     Six fixed steps plus one fluid display size, replacing 13 ad-hoc values
     with quarter-point increments. No half-pixels. */
  --fs-micro: 11px;           /* badges, pills, counts, table headers */
  --fs-label: 12px;           /* the archive voice: .label, .chip, .btn, .tab */
  --fs-sm: 14px;              /* aliases, meta rows, hints, captions, code */
  --fs-body: 16px;            /* default body, rendered prose */
  --fs-title: 20px;           /* section headings, .md h2 */
  --fs-h1: 26px;              /* in-content h1 (rendered docs) */
  /* Handoff type steps that fall between the six fixed sizes above. styles.css
     declares no raw font-size; these carry the remaining scale. Rendered-prose
     headings stay em-based so --reading-scale keeps working. */
  --fs-10: 10px;             /* micro badges: reference cover tag */
  --fs-13: 13px;             /* alias, caption, file names — recede without dropping contrast */
  --fs-15: 15px;             /* compact-card name, wordmark, document card title */
  --fs-17: 17px;             /* big-card name, inspector name, document prose */
  --fs-19: 19px;             /* panel subheading */
  --fs-22: 22px;             /* rendered .md h2 */
  --fs-38: 38px;             /* rendered document h1 */
  --fs-44: 44px;             /* character name at the 3A head */
  --fs-88: 88px;             /* the framed initial on a wall plate with no cover */
  --fs-page: clamp(28px, 2.2vw, 34px); /* directory heading */
  --fs-display: clamp(32px, 3vw, 48px); /* the one page title */

  /* 16px at every width, not just below 768: iPadOS Safari zooms on focus at
     1024 too, so a breakpoint-scoped fix leaves the tablet case broken. */
  --fs-input: 16px;

  /* Geist sits second on purpose: if the Plus Jakarta Sans file is slow to load the
     reading voice degrades to the interface face rather than all the way to system-ui. */
  --font-sans: "Plus Jakarta Sans", "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-ui: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  /* The micro-label voice. It ran in Geist Mono; it now runs in the same Geist as
     the rest of the interface — the uppercase tracking is what makes these read as
     labels, not the fixed width.

     --font-code follows it by request, so nothing on the page is fixed-width any
     more. That is a real trade: code blocks in rendered documents lose column
     alignment, and `l`/`1`/`I` and `0`/`O` stop being distinguishable in a slug or
     an ID. Kept as its own token so code can go back to a mono stack on its own —
     set it to `ui-monospace, SFMono-Regular, Menlo, Consolas, monospace`. */
  --font-label: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-code: var(--font-label);
  /* The wordmark only, always Bold (700) with -0.01em tracking — the logo's own
     setting. If the file fails to load, the wordmark falls back to the reading voice. */
  --font-logo: "Plus Jakarta Sans", var(--font-sans);

  /* ---------- spacing: 4px grid, name = px / 4 ---------- */
  --sp-05: 2px;               /* the one sub-grid step: vertical padding on inline pills */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-2-5: 10px;             /* 2px-grid step: 2A card stat-row gap */
  --sp-3: 12px;
  --sp-3-5: 14px;             /* 2px-grid step: 2A big-card body padding */
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 28px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-12: 48px;
  --sp-16: 64px;
  --sp-20: 80px;
  --sp-24: 96px;

  /* ---------- radius ---------- */
  --radius-xs: 3px;           /* nested chips inside a control */
  --radius-sm: 6px;           /* kbd, thumbnails inside rows, badges */
  --radius: 10px;             /* the product radius: controls, cards, inputs */
  --radius-md: 12px;          /* media cards: reference tiles, doc-rail cards */
  --radius-lg: 16px;          /* modals, palette, tray */
  --radius-full: 999px;       /* chips, tags, pills */
  --radius-sheet: 20px;       /* top corners of a phone bottom sheet — the one radius above --radius-lg */

  /* ---------- geometry ----------
     One knob for every hit area. 40px is the dense-desktop floor; the media
     query below raises it to the 44px touch floor, and --topbar-h follows. */
  --hit: 40px;
  --topbar-h: calc(var(--hit) + var(--sp-3) * 2);
  --page-max: 1760px;
}

/* Dark and every .art-zone glow brighter: the same accent needs more spread to read
   on a dark ground. */
:root[data-theme="dark"],
.art-zone {
  --glow: 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent),
    0 2px 12px color-mix(in srgb, var(--accent) 22%, transparent),
    0 10px 40px color-mix(in srgb, var(--accent) 18%, transparent);
  --glow-soft: 0 2px 14px color-mix(in srgb, var(--accent) 16%, transparent),
    0 12px 44px color-mix(in srgb, var(--accent) 12%, transparent);
  --ambient: radial-gradient(
    90rem 44rem at 50% -16rem,
    color-mix(in srgb, var(--accent) 10%, transparent),
    transparent 65%
  );
}

/* Touch floor. Raising --hit here resizes every control at once. The phone top bar is
   a 44px row with 8px above and below (60px), tighter than the desktop 64px. */
@media (max-width: 767px) {
  :root { --hit: 44px; --topbar-h: calc(var(--hit) + var(--sp-4)); }
}

html { color-scheme: light; }

/* LOREHOUSE · colour palettes — GENERATED by palette.py. Do not edit by hand.
   Paste into public/tokens.css in place of the old light and dark colour blocks.
   <html data-palette> picks the palette (sianotip is the default), <html data-theme="dark">
   picks dark. Anything inside .art-zone (hero, lightbox, landing hero, login art) always
   takes the dark values of the active palette, because its text sits on artwork. */

/* Sianotip — Cetak biru lembar desain karakter: kertas biru pucat, tinta Prussia, kobalt untuk aksi. */
:root[data-palette="sianotip"],
:root:not([data-palette]) {
  --bg: #f1f7fc;
  --bg-app: #e7eef5;
  --surface: #fbfdff;
  --surface-2: #e1eaf2;
  --line: #d1dae3;
  --line-strong: #b7c4d0;
  --line-control: #697b8d;
  --text: #112038;
  --muted: #44566a;
  --faint: #526275;
  --accent: #2151bb;
  --accent-display: #2860dd;
  --accent-dim: #c2d7fb;
  --accent-wash: #e4edfe;
  --moss: #006566;
  --moss-wash: #d4f0f0;
  --danger: #bc2122;
  --danger-wash: #ffe6e3;
  --on-accent: #fcfeff;
  --on-art: #f7fbfe;
  --hero-ground: #122239;
  --float: rgb(249 252 255 / 0.92);
  --on-float: #112038;
  --tooltip: #0d1d34;
  --on-tooltip: #f5f9fc;
  --scrim: rgb(5 21 46 / 0.62);
  --backdrop: rgb(7 22 44 / 0.46);
  --backdrop-soft: rgb(7 22 44 / 0.28);
  --shadow: 0 1px 2px rgb(18 34 57 / 0.05),0 10px 28px rgb(18 34 57 / 0.08);
  --shadow-lg: 0 28px 72px rgb(18 34 57 / 0.22);
}
:root[data-palette="sianotip"][data-theme="dark"],
:root[data-palette="sianotip"] .art-zone,
:root:not([data-palette])[data-theme="dark"],
:root:not([data-palette]) .art-zone {
  --bg: #0a1422;
  --bg-app: #060f1b;
  --surface: #111c2b;
  --surface-2: #192536;
  --line: #24303f;
  --line-strong: #354254;
  --line-control: #6a7e93;
  --text: #e6eef4;
  --muted: #abb8c3;
  --faint: #97a5b1;
  --accent: #7eb5ff;
  --accent-display: #7eb5ff;
  --accent-dim: #273f67;
  --accent-wash: #16253d;
  --moss: #75ccc7;
  --moss-wash: #0d3030;
  --danger: #f57870;
  --danger-wash: #411e1c;
  --on-accent: #09162a;
  --on-art: #f4f7fb;
  --hero-ground: #050e1a;
  --float: rgb(17 28 43 / 0.9);
  --on-float: #e6eef4;
  --tooltip: #e6eef4;
  --on-tooltip: #0a1628;
  --scrim: rgb(1 5 19 / 0.7);
  --backdrop: rgb(0 1 8 / 0.6);
  --backdrop-soft: rgb(0 1 8 / 0.4);
  --shadow: 0 0 0 0 transparent;
  --shadow-lg: 0 24px 64px rgb(0 0 0 / 0.55);
}

/* Riso — Zine fandom cetak risograf: kertas putih netral, tinta hitam, merah muda fluoresens dan teal. */
:root[data-palette="riso"] {
  --bg: #f7f6f9;
  --bg-app: #efeef2;
  --surface: #fefdff;
  --surface-2: #ebe9ef;
  --line: #dbdadf;
  --line-strong: #c7c4cc;
  --line-control: #7a7781;
  --text: #17151c;
  --muted: #545159;
  --faint: #615f67;
  --accent: #c91571;
  --accent-display: #ea2486;
  --accent-dim: #fdc8db;
  --accent-wash: #ffe8f0;
  --moss: #006973;
  --moss-wash: #d5f1f5;
  --danger: #b53700;
  --danger-wash: #ffe7df;
  --on-accent: #fefeff;
  --on-art: #fcfbfe;
  --hero-ground: #1c151e;
  --float: rgb(254 253 255 / 0.92);
  --on-float: #17151c;
  --tooltip: #17151c;
  --on-tooltip: #faf9fc;
  --scrim: rgb(25 9 21 / 0.6);
  --backdrop: rgb(19 13 21 / 0.44);
  --backdrop-soft: rgb(19 13 21 / 0.26);
  --shadow: 0 1px 2px rgb(23 21 28 / 0.05),0 10px 28px rgb(23 21 28 / 0.08);
  --shadow-lg: 0 28px 72px rgb(23 21 28 / 0.22);
}
:root[data-palette="riso"][data-theme="dark"],
:root[data-palette="riso"] .art-zone {
  --bg: #111014;
  --bg-app: #0c0b0e;
  --surface: #19181c;
  --surface-2: #232127;
  --line: #2f2d33;
  --line-strong: #413e46;
  --line-control: #7d7a85;
  --text: #f1eff4;
  --muted: #b7b4bc;
  --faint: #a4a1aa;
  --accent: #fc7bac;
  --accent-display: #fc7bac;
  --accent-dim: #652742;
  --accent-wash: #391826;
  --moss: #6eccd1;
  --moss-wash: #0b2e32;
  --danger: #f4875c;
  --danger-wash: #402219;
  --on-accent: #190d15;
  --on-art: #f9f8fb;
  --hero-ground: #0d0a0e;
  --float: rgb(25 24 28 / 0.9);
  --on-float: #f1eff4;
  --tooltip: #f1eff4;
  --on-tooltip: #121115;
  --scrim: rgb(10 2 8 / 0.68);
  --backdrop: rgb(1 1 2 / 0.6);
  --backdrop-soft: rgb(1 1 2 / 0.4);
  --shadow: 0 0 0 0 transparent;
  --shadow-lg: 0 24px 64px rgb(0 0 0 / 0.55);
}

/* Fosfor — Tinta ungu tua dan cahaya fosfor: menyala penuh di mode gelap, jadi stabilo di mode terang. */
:root[data-palette="fosfor"] {
  --bg: #f7f2f9;
  --bg-app: #efe8f1;
  --surface: #fdfbfe;
  --surface-2: #ece4ef;
  --line: #ddd4e0;
  --line-strong: #c9becd;
  --line-control: #827087;
  --text: #29152f;
  --muted: #604e66;
  --faint: #6a596f;
  --accent: #6c2b8d;
  --accent-display: #addb1d;
  --accent-dim: #d1f46e;
  --accent-wash: #eefacd;
  --moss: #0a6c49;
  --moss-wash: #d8f3e4;
  --danger: #ba2a31;
  --danger-wash: #ffe6e4;
  --on-accent: #fdfbfd;
  --on-art: #fafbf5;
  --hero-ground: #1f0e24;
  --float: rgb(253 251 254 / 0.92);
  --on-float: #29152f;
  --tooltip: #241229;
  --on-tooltip: #d5f96e;
  --scrim: rgb(26 5 32 / 0.62);
  --backdrop: rgb(24 7 29 / 0.46);
  --backdrop-soft: rgb(24 7 29 / 0.28);
  --shadow: 0 1px 2px rgb(43 21 49 / 0.05),0 10px 28px rgb(43 21 49 / 0.08);
  --shadow-lg: 0 28px 72px rgb(43 21 49 / 0.22);
}
:root[data-palette="fosfor"][data-theme="dark"],
:root[data-palette="fosfor"] .art-zone {
  --bg: #150b18;
  --bg-app: #0f0612;
  --surface: #1e1222;
  --surface-2: #291b2d;
  --line: #35283a;
  --line-strong: #49394e;
  --line-control: #8b7893;
  --text: #eef0e2;
  --muted: #beb4c7;
  --faint: #aca1b5;
  --accent: #c6f453;
  --accent-display: #c6f453;
  --accent-dim: #3a4b0f;
  --accent-wash: #20290c;
  --moss: #c1a9ee;
  --moss-wash: #352448;
  --danger: #f67878;
  --danger-wash: #472020;
  --on-accent: #190b1d;
  --on-art: #f7f8ef;
  --hero-ground: #0e0511;
  --float: rgb(30 18 34 / 0.9);
  --on-float: #eef0e2;
  --tooltip: #c6f453;
  --on-tooltip: #190b1d;
  --scrim: rgb(10 1 14 / 0.7);
  --backdrop: rgb(3 0 4 / 0.62);
  --backdrop-soft: rgb(3 0 4 / 0.42);
  --shadow: 0 0 0 0 transparent;
  --shadow-lg: 0 24px 64px rgb(0 0 0 / 0.55);
}

:root[data-theme="dark"], .art-zone { color-scheme: dark; }

/* `color` inherits as a computed value, so text inside an .art-zone would keep the
   page's ink (dark on dark in the light theme) unless the zone re-reads --text. */
.art-zone { color: var(--text); }

/* The page's own colours, captured once on :root. A var() resolves where it is declared,
   so these keep the page values all the way down, inside an .art-zone too, where
   --surface and the rest are the dark ones. .page-tokens puts them back on a subtree:
   a popover that opens out of artwork onto the page (the hero's ⋯ menu — F-Menu-Prompt
   draws it on the page ground). The hero reads a few of them directly: its ground,
   scrim, plate and "Unggah" follow the page theme, as the boards draw them. No new
   colour: every value is a role above. */
:root {
  --page-bg: var(--bg);
  --page-surface: var(--surface);
  --page-surface-2: var(--surface-2);
  --page-line: var(--line);
  --page-line-strong: var(--line-strong);
  --page-line-control: var(--line-control);
  --page-text: var(--text);
  --page-muted: var(--muted);
  --page-faint: var(--faint);
  --page-accent: var(--accent);
  --page-on-accent: var(--on-accent);
  --page-danger: var(--danger);
  --page-danger-wash: var(--danger-wash);
  --page-shadow: var(--shadow);
  --page-shadow-lg: var(--shadow-lg);
  /* the hero keeps these four too (Karakter, F-Karakter-Kosong; handoff D7) */
  --page-hero-ground: var(--hero-ground);
  --page-scrim: var(--scrim);
  --page-float: var(--float);
}
.page-tokens {
  --bg: var(--page-bg);
  --surface: var(--page-surface);
  --surface-2: var(--page-surface-2);
  --line: var(--page-line);
  --line-strong: var(--page-line-strong);
  --line-control: var(--page-line-control);
  --text: var(--page-text);
  --muted: var(--page-muted);
  --faint: var(--page-faint);
  --accent: var(--page-accent);
  --on-accent: var(--page-on-accent);
  --danger: var(--page-danger);
  --danger-wash: var(--page-danger-wash);
  --shadow: var(--page-shadow);
  --shadow-lg: var(--page-shadow-lg);
  color: var(--text);
  color-scheme: light;
}
:root[data-theme="dark"] .page-tokens { color-scheme: dark; }
