/* nanofable demo — storybook-on-parchment. Tokens from the design plan: parchment ground, ink text, quill-blue accent, gilt for the illuminated touches. */ /* Self-hosted fonts (latin subsets), preloaded from index.html so they're ready at first paint — no swap-reflow on load, and no third-party request. */ @font-face { font-family: "IM Fell English"; font-style: normal; font-weight: 400; font-display: swap; src: url("fonts/im-fell-english.woff2") format("woff2"); } @font-face { font-family: "IM Fell English"; font-style: italic; font-weight: 400; font-display: swap; src: url("fonts/im-fell-english-italic.woff2") format("woff2"); } @font-face { font-family: "EB Garamond"; font-style: normal; font-weight: 400 600; font-display: swap; src: url("fonts/eb-garamond.woff2") format("woff2"); } @font-face { font-family: "EB Garamond"; font-style: italic; font-weight: 400 600; font-display: swap; src: url("fonts/eb-garamond-italic.woff2") format("woff2"); } :root { --parchment: #f6f1e5; --vellum: #fbf8f0; --ink: #2e2a24; --faded: #857b6b; --quill: #3a5169; --gilt: #b08d3e; --madder: #8c3b2e; /* error accent only */ --line: rgba(46, 42, 36, 0.14); --font-display: "IM Fell English", "Iowan Old Style", serif; --font-body: "EB Garamond", Georgia, serif; --font-ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; --col: 44rem; } * { box-sizing: border-box; margin: 0; } html, body { height: 100%; } body { display: flex; flex-direction: column; background: var(--parchment); color: var(--ink); font-family: var(--font-body); font-size: 17px; } /* ---- header ---- */ .site-head { display: flex; align-items: center; justify-content: space-between; padding: 0.9rem 1.25rem; } .mark { font-family: var(--font-display); font-size: 1.15rem; letter-spacing: 0.02em; } .mark-sub { color: var(--faded); font-style: italic; font-size: 0.95rem; } .icon-btn { display: grid; place-items: center; width: 2.4rem; height: 2.4rem; border: 1px solid var(--line); border-radius: 50%; background: var(--vellum); color: var(--quill); cursor: pointer; } .icon-btn:hover { border-color: var(--quill); } .icon-btn:disabled { color: var(--faded); cursor: default; border-color: var(--line); } .icon-btn.done { color: var(--gilt); } /* ---- main / hero / transcript ---- */ #main { flex: 1; overflow-y: auto; padding: 0 1.25rem; } #hero { max-width: var(--col); margin: 12vh auto 0; text-align: center; } body.storytime #hero { display: none; } .hero-bard { width: 93px; /* the art's native pixel grid (465 / 5) — keeps pixels even */ height: auto; image-rendering: pixelated; margin-top: 1.5rem; } .hero-title { font-family: var(--font-display); font-weight: 400; font-size: clamp(2.1rem, 6vw, 3.3rem); line-height: 1.15; } .hero-sub { margin: 1.1rem auto 0; max-width: 34rem; color: var(--faded); font-size: 1.05rem; line-height: 1.55; } #transcript { max-width: var(--col); margin: 0 auto; padding: 1.5rem 0 2rem; } .entry-user { margin-top: 2.25rem; font-family: var(--font-ui); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--faded); } .story { margin-top: 0.8rem; font-size: 1.16rem; line-height: 1.72; white-space: pre-wrap; overflow-wrap: anywhere; /* unbroken token runs (e.g. "NNNN…") wrap, never overflow */ } /* Raised initial: inline so it shares the first line's baseline — the line sits level with the letter's bottom, and the letter towers above it. */ .story .dropcap { font-family: var(--font-display); font-size: 2.9em; line-height: 1; padding-right: 0.06em; color: var(--gilt); } .story.streaming::after { content: ""; display: inline-block; width: 2px; height: 1em; margin-left: 2px; vertical-align: -0.15em; background: var(--quill); animation: inkblink 1.1s steps(2, start) infinite; } @keyframes inkblink { to { visibility: hidden; } } .story-note { margin-top: 0.6rem; font-family: var(--font-ui); font-size: 0.75rem; color: var(--faded); } .fin { margin-top: 0.9rem; text-align: center; color: var(--gilt); font-size: 1rem; } /* ---- composer ---- */ .composer-wrap { padding: 0 1.25rem calc(0.75rem + env(safe-area-inset-bottom)); } .composer { max-width: var(--col); margin: 0 auto; background: var(--vellum); border: 1px solid var(--line); border-radius: 16px; box-shadow: 0 2px 14px rgba(46, 42, 36, 0.07); padding: 0.85rem 0.9rem 0.65rem; } .composer:focus-within { border-color: var(--quill); } #input { width: 100%; border: 0; background: transparent; resize: none; font-family: var(--font-body); font-size: 1.08rem; line-height: 1.5; color: var(--ink); max-height: 9rem; } #input:focus { outline: none; } #input::placeholder { color: var(--faded); font-style: italic; } .composer-row { display: flex; align-items: flex-end; justify-content: space-between; margin-top: 0.55rem; gap: 0.5rem; } .composer-tools { display: flex; gap: 0.4rem; } .menu-anchor { position: relative; } .chip { display: inline-flex; align-items: center; justify-content: center; gap: 0.35rem; font-family: var(--font-ui); font-size: 0.78rem; color: var(--ink); background: transparent; border: 1px solid var(--line); border-radius: 999px; padding: 0.34rem 0.75rem; cursor: pointer; white-space: nowrap; } /* Reserve the chip's width up front so "loading…" -> model name doesn't reflow. */ #model-btn { min-width: 11.5rem; } .chip:hover:not(:disabled) { border-color: var(--quill); color: var(--quill); } .chip:disabled { color: var(--faded); cursor: default; } .chip-icon { padding: 0.34rem 0.55rem; } .send { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border: 0; border-radius: 50%; background: var(--quill); color: var(--parchment); cursor: pointer; flex: 0 0 auto; } .send:hover:not(:disabled) { background: #2e4157; } .send:disabled { background: var(--line); color: var(--faded); cursor: default; } .send .ic-stop { display: none; } body.generating .send .ic-stop { display: block; } body.generating .send .ic-quill { display: none; } .colophon { max-width: var(--col); margin: 0.5rem auto 0; text-align: center; font-family: var(--font-ui); font-size: 0.7rem; letter-spacing: 0.04em; color: var(--faded); } /* ---- menus ---- */ .menu { position: absolute; bottom: calc(100% + 0.5rem); left: 0; min-width: 15rem; background: var(--vellum); border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 6px 24px rgba(46, 42, 36, 0.14); padding: 0.4rem; z-index: 20; font-family: var(--font-ui); } .menu-heading { font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--faded); padding: 0.35rem 0.6rem 0.45rem; } .menu-item { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; width: 100%; border: 0; background: transparent; border-radius: 8px; padding: 0.45rem 0.6rem; font-size: 0.82rem; color: var(--ink); cursor: pointer; text-align: left; } .menu-item:hover:not(:disabled) { background: rgba(58, 81, 105, 0.08); } .menu-item:disabled { color: var(--faded); cursor: not-allowed; } .menu-item .size { color: var(--faded); font-size: 0.74rem; } .menu-item.selected { color: var(--quill); font-weight: 600; } .menu-item.selected::before { content: "✓ "; } .menu-row { display: block; position: relative; } .menu-tip { position: absolute; left: calc(100% + 0.5rem); top: 50%; transform: translateY(-50%); width: 12rem; background: var(--ink); color: var(--parchment); border-radius: 8px; padding: 0.4rem 0.55rem; font-size: 0.72rem; line-height: 1.35; box-shadow: 0 6px 24px rgba(46, 42, 36, 0.18); opacity: 0; visibility: hidden; transition: opacity 0.12s ease; pointer-events: none; z-index: 30; } .menu-row.locked:hover .menu-tip { opacity: 1; visibility: visible; } .menu-config label { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.3rem 0.6rem; font-size: 0.82rem; } .menu-config .hint { color: var(--faded); font-size: 0.72rem; } .menu-config input { width: 4.6rem; font-family: var(--font-ui); font-size: 0.82rem; color: var(--ink); background: var(--parchment); border: 1px solid var(--line); border-radius: 6px; padding: 0.25rem 0.4rem; } /* ---- toasts (bottom-left) & progress (bottom-right) ---- */ #toast-region { position: fixed; bottom: 1rem; left: 1rem; display: flex; flex-direction: column; gap: 0.5rem; z-index: 40; max-width: min(22rem, calc(100vw - 2rem)); pointer-events: none; /* toasts are read-only; never block the composer under them */ } .toast { background: var(--vellum); border: 1px solid var(--line); border-left: 3px solid var(--madder); border-radius: 10px; box-shadow: 0 4px 18px rgba(46, 42, 36, 0.12); padding: 0.6rem 0.85rem; font-family: var(--font-ui); font-size: 0.82rem; line-height: 1.45; } #progress-card { position: fixed; bottom: 1rem; right: 1rem; width: min(19rem, calc(100vw - 2rem)); background: var(--vellum); border: 1px solid var(--line); border-radius: 12px; box-shadow: 0 4px 18px rgba(46, 42, 36, 0.12); padding: 0.75rem 0.9rem; font-family: var(--font-ui); z-index: 40; } .progress-title { font-size: 0.68rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--faded); } .progress-label { font-size: 0.82rem; margin-top: 0.35rem; } .progress-track { height: 4px; margin-top: 0.5rem; border-radius: 2px; background: var(--line); overflow: hidden; } .progress-fill { height: 100%; width: 0; border-radius: 2px; background: var(--quill); transition: width 0.15s ease-out; } .progress-overall { font-size: 0.72rem; color: var(--faded); margin-top: 0.4rem; } /* ---- a11y & responsive ---- */ :focus-visible { outline: 2px solid var(--quill); outline-offset: 2px; } @media (prefers-reduced-motion: reduce) { .story.streaming::after { animation: none; } .progress-fill { transition: none; } } @media (max-width: 540px) { #hero { margin-top: 7vh; } .site-head, #main, .composer-wrap { padding-left: 0.8rem; padding-right: 0.8rem; } .chip { font-size: 0.72rem; padding: 0.3rem 0.6rem; } }