/* QuickWrite — typography, palette, layout. Values per wordoutline.md §4/§6. */

@font-face {
    font-family: "iA Writer Mono S";
    src: url("fonts/iAWriterMonoS-Regular.woff2") format("woff2");
    font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
    font-family: "iA Writer Mono S";
    src: url("fonts/iAWriterMonoS-Italic.woff2") format("woff2");
    font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
    font-family: "iA Writer Mono S";
    src: url("fonts/iAWriterMonoS-Bold.woff2") format("woff2");
    font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
    font-family: "iA Writer Mono S";
    src: url("fonts/iAWriterMonoS-BoldItalic.woff2") format("woff2");
    font-weight: 700; font-style: italic; font-display: swap;
}

:root {
    /* Light — the shipped palette (§4.2). */
    --bg:    #ffffff;
    --fg:    #222324;
    --mk:    #aeb1b5;
    --muted: #aeb1b5;
    --link:  #2077b2;
    --code:  #f8f8f8;
    --sel:   rgba(32, 119, 178, 0.22);

    --size: 20px;
    --lh: 1.5;

    /* Chrome runs at 75% of the editor text. omawrite reuses the editor's exact
       font size for its word count; here the chrome is deliberately subordinate
       to the writing, so it reads as furniture rather than content. */
    --chrome: 15px;
}

/* Dark is defined but deliberately unwired — see wordoutline.md D3. Enabling it
   is one media query (or one class on <html>) and no other change. */
.theme-dark {
    --bg:    #101010;
    --fg:    #eeeeee;
    --mk:    #4f525a;
    --muted: #909191;
    --link:  #5584aa;
    --code:  #1c1a1a;
    --sel:   rgba(85, 132, 170, 0.28);
}

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

html { background: var(--bg); }

body {
    min-height: 100dvh;
    background: var(--bg);
    color: var(--fg);
    font-family: "iA Writer Mono S", "IBM Plex Mono", ui-monospace, monospace;
    font-size: var(--size);
    line-height: var(--lh);
    /* Real bold and italic faces are loaded, so synthesis is never wanted. A
       synthesised face has different metrics and would desynchronise the
       mirror from the textarea (§3.1). */
    font-synthesis: none;
    -webkit-font-synthesis: none;
}

/* ── The column ────────────────────────────────────────────────────────────
   65ch is exact here: `ch` is the advance of "0", which in a monospace face
   is the cell width. No JS measurement needed (§4.1).
   The 24px side margins come from the viewport subtraction. */
.col {
    position: relative;
    width: min(65ch, calc(100vw - 48px));
    /* Top margin clears .topbar, including a notch's inset — otherwise the
       first line sits under the save indicator at rest, not just while
       scrolling. */
    margin: calc(64px + env(safe-area-inset-top)) auto 96px;
}

/* The mirror and the textarea must agree on every property that affects
   layout: font, width, padding (both zero), letter-spacing, tab-size, and
   wrapping. Anything asymmetric here shows up as drifting caret alignment
   toward the bottom of a long document. */
.mirror,
.input {
    font: inherit;
    font-family: inherit;
    line-height: inherit;
    letter-spacing: 0;
    tab-size: 4;
    width: 100%;
    padding: 0;
    border: 0;
    white-space: pre-wrap;
    overflow-wrap: break-word;
    word-break: normal;
}

/* The mirror sits in normal flow and therefore *defines the height of the
   column*. The textarea is stretched over it. This is why there is no
   scroll-sync code anywhere: neither element scrolls internally, the page
   does. */
.mirror {
    min-height: 60vh;
    color: var(--fg);
    /* Purely decorative. The textarea holds the real text; without this a
       screen reader would read the document twice (§10). */
    user-select: none;
    pointer-events: none;
}

.input {
    position: absolute;
    inset: 0;
    height: 100%;
    resize: none;
    overflow: hidden;
    background: transparent;
    caret-color: var(--fg);
    outline: none;
    /* NOTE: text is deliberately *visible* here. See .js-ready below. */
    color: var(--fg);
}

/* The glyphs you normally see come from the mirror, not the textarea — so the
   textarea's own text is hidden. But that hiding is gated on the app having
   actually booted.
 *
 * Hiding it unconditionally means any JS failure — a stale cache serving a
 * mismatched module, a syntax error, a blocked script — turns the editor into a
 * box that swallows everything you type: no visible text, and no caret until
 * you click. Gating on .js-ready degrades to a plain, ugly, entirely usable
 * textarea instead. The class is added only after the first successful paint.
 *
 * iOS needs the -webkit- property; the standard one alone has no effect there. */
.js-ready .input {
    color: transparent;
    -webkit-text-fill-color: transparent;
}

.input::selection { background: var(--sel); }
.input::placeholder { color: var(--mk); opacity: 1; }

/* Heading glyphs are wider than the textarea's single fixed character grid.
   Hide its caret and place this one from the matching text in the rendered
   mirror, including normal or empty lines after headings. */
.input.has-visual-caret { caret-color: transparent; }
.visual-caret {
    position: absolute;
    z-index: 2;
    width: 1px;
    background: var(--fg);
    pointer-events: none;
    animation: caret-blink 1s steps(1, end) infinite;
}
@keyframes caret-blink { 50% { opacity: 0; } }

/* ── Highlight classes (§5) ─────────────────────────────────────────────── */
.mirror .mk   { color: var(--mk); }                        /* dimmed markers */
.mirror .h    { font-weight: 700; }
/* Keep the existing 30px line box, but let the larger monospace faces use their
   natural character spacing so letters remain distinct rather than crowding. */
.mirror .h1   { font-size: 1.5em;  line-height: 1;   vertical-align: top; }
.mirror .h2   { font-size: 1.25em; line-height: 1.2; vertical-align: top; }
.mirror .q    { color: var(--mk); font-style: italic; }     /* blockquote */
.mirror .hr   { color: var(--mk); }                        /* horizontal rule */
.mirror .b    { font-weight: 700; }
.mirror .i    { font-style: italic; }
.mirror .a    { color: var(--link); text-decoration: underline; }
.mirror .code { background: var(--code); }

/* ── Top bar: save state only (§6) ─────────────────────────────────────── */
.topbar {
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: calc(10px + env(safe-area-inset-top)) 12px 10px 12px;
    color: var(--muted);
    font-size: var(--chrome);
    line-height: 1;
    /* Opaque, so text scrolling underneath is masked rather than colliding
       with the indicator. Same approach as the footer. */
    background: var(--bg);
}

.bar a {
    color: var(--muted);
    text-decoration: none;
    padding: 2px 4px;
    border-radius: 3px;
}
.bar a:hover { color: var(--fg); }
.bar a:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }

/* Deliberately NOT faded by .is-typing, unlike the footer. Typing is exactly
   when the save state changes, so hiding it then would defeat the point of
   giving it its own corner. */

/* ── Footer (§6) ───────────────────────────────────────────────────────── */
.bar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom)) 12px;
    color: var(--muted);
    font-size: var(--chrome);
    line-height: 1;
    background: var(--bg);
    transition: opacity 0.25s ease;
}

.bar-left, .bar-right { display: flex; align-items: center; gap: 12px; }
.bar-right { text-align: right; }

.bar button {
    font: inherit;
    font-family: inherit;
    color: var(--muted);
    background: none;
    border: 0;
    padding: 2px 4px;
    cursor: pointer;
    border-radius: 3px;
}
.bar button:hover { color: var(--fg); }
.bar button:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }

.warn { color: var(--link); }
[hidden] { display: none !important; }

/* The `?` reads as a glyph rather than a control, so give it a fixed square
   footprint instead of letting the character's own width define it. */
#help {
    width: 1.6em;
    text-align: center;
}
#help .ph { font-size: 1.05em; }

/* ── Shortcuts panel (§8.2) ────────────────────────────────────────────── */
.sheet {
    position: fixed;
    left: 12px;
    /* Clears the footer row with 8px to spare, so the panel reads as its own
       surface rather than abutting the chrome. */
    bottom: calc(52px + env(safe-area-inset-bottom));
    z-index: 2;
    max-width: calc(100vw - 24px);
    /* Seven 44px rows plus the hint exceeds a landscape phone's height, so the
       panel scrolls rather than running off the top of the screen. */
    max-height: calc(100dvh - 80px);
    overflow-y: auto;
    padding: 12px 16px;
    /* Part of the bottom chrome — it hangs off the footer, so it tracks the
       chrome size rather than the editor's. Touch targets are set in px and are
       unaffected. */
    font-size: var(--chrome);
    background: var(--code);
    border-radius: 4px;
    color: var(--fg);
    line-height: 1.5;
}

/* No min-width: the items size to their content, which lands around 272px and
   stays inside the sheet's max-width on the narrowest phones. A fixed 16em
   would be 320px here and overflow a 320px viewport. */
.menu { list-style: none; }

.menu button {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 32px;
    width: 100%;
    /* 44px is the accepted floor for a touch target, and this panel exists
       primarily so the app is usable without a keyboard. */
    min-height: 44px;
    padding: 4px 8px;
    font: inherit;
    font-family: inherit;
    text-align: left;
    color: var(--fg);
    background: none;
    border: 0;
    border-radius: 3px;
    cursor: pointer;
}

.menu button:hover,
.menu button:focus-visible { background: var(--bg); }
.menu button:focus-visible { outline: 2px solid var(--link); outline-offset: -2px; }

.menu .k { color: var(--muted); }

.hint {
    max-width: 16em;
    margin-top: 10px;
    padding: 0 8px;
    color: var(--muted);
    /* 0.7em of the old 20px was 14px; against the smaller chrome it would be
       10.5px, which is past readable. */
    font-size: 0.85em;
    line-height: 1.6;
}

/* Chrome recedes while typing and returns on pointer move. Gated on a real
   pointer: with (hover: none) there is no way to bring it back (§11). */
@media (hover: hover) {
    body.is-typing .bar { opacity: 0.4; }
}

@media (prefers-reduced-motion: reduce) {
    .bar { transition: none; }
    .visual-caret { animation: none; }
}
