/* The cabinet around the canvas.
 *
 * Everything here is measured in GAME PIXELS, not CSS pixels. The engine sets
 * two custom properties on the cabinet and every size in this file is written
 * against them:
 *
 *   --s   one game pixel, in CSS pixels. The canvas's integer scale.
 *   --t   the text scale: 1 or 2. The face is drawn on an 8px grid, so the
 *         only font sizes that stay crisp are 8px and 16px. Anything between
 *         is a blurred bitmap font, which is worse than a clean small one.
 *
 * So a 1px border is calc(1px * var(--t)) and the sidebar is 104 game pixels
 * wide, and the whole cabinet grows in whole steps with the picture. Nothing
 * here is sized in rem: a rem has nothing to do with a game pixel, and mixing
 * the two is how the chrome stopped looking like the game. */

/* Northrup, by novov: a pixel face in the lineage of the console RPGs rather
 * than the DOS terminal. It replaced Web437 IBM BIOS, which was VileR's
 * remake of the IBM PC BIOS 8x8 ROM font - the face Sierra's AGI interpreter
 * drew with on DOS. That one was the more literally accurate choice and this
 * one is the better-looking one; the file is still in css/fonts/ if that
 * trade ever wants reversing.
 *
 * Self-hosted rather than fetched from a CDN, so the cabinet cannot silently
 * fall back to Courier New.
 *
 * SIL Open Font License 1.1 - see fonts/Northrup-OFL.txt.
 * https://github.com/mirnovov/northrup
 *
 * Native size is 16px, and that is not a style choice. Northrup is built with
 * an em of 1024 units and 64 units to the bitmap pixel, so one font pixel is
 * exactly a sixteenth of an em: at 16px a pixel is a pixel, at 32px it is two,
 * and at any size between the glyphs are resampled and go soft. Every text
 * size here is therefore a multiple of --fp, the font pixel, and never a
 * round CSS number that happens to look close.
 *
 * The glyph box is 15 of those pixels - 12 above the baseline and 3 below -
 * with a cap height of 9 and an x-height of 6. It is proportional, not fixed
 * width, which is the one way it does not behave like the font it replaced.
 *
 * Northrup covers Latin, Greek and Cyrillic and no symbols at all: no em
 * dash, no ellipsis, no box drawing, nothing in the arrows or the geometric
 * blocks. Anything the cabinet needs that is not a letter is either written
 * in ASCII or drawn in CSS - see .quests-drawer-toggle. Putting a character
 * it does not have on the screen falls back to a system font, which is a
 * smooth glyph in the middle of a pixel one and reads as a bug. */
@font-face {
    font-family: "Northrup Regular";
    src: url("fonts/NorthrupRegular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: block;
}

:root {
    --quests-font: "Northrup Regular", "Courier New", monospace;

    /* One font pixel. The engine overwrites this on the cabinet with 1px or
       2px; the value here is only what the page looks like before the first
       resize. Text is sized in these, not in CSS pixels. */
    --fp: 1px;

    /* EGA, and only EGA. The chrome has no business using a colour the game
     * could not draw. */
    --ega-black:      #000000;
    --ega-white:      #FFFFFF;
    --ega-light-grey: #AAAAAA;
    --ega-dark-grey:  #555555;
    --ega-yellow:     #FFFF55;
    --ega-cyan:       #55FFFF;
    --ega-blue:       #5555FF;
    --ega-red:        #FF5555;
    --ega-brown:      #AA5500;
}

.quests-cabinet {
    --s: 2;          /* the engine overwrites both of these on every resize */
    --t: 1;
}

/* Hard edges everywhere. One rounded corner anywhere in the cabinet and the
 * whole thing stops reading as a 1989 screen.
 *
 * border-box throughout, so a width written as 104 game pixels is 104 game
 * pixels on the screen with its white rule inside it, not 104 plus however
 * many the border came to. */
.quests-cabinet,
.quests-cabinet * {
    box-sizing: border-box;
    border-radius: 0 !important;
    font-family: var(--quests-font);
    font-weight: 400;
    font-synthesis: none;
    -webkit-font-smoothing: none;
    -moz-osx-font-smoothing: grayscale;
    font-smooth: never;
    letter-spacing: 0;

    /* Northrup's space is one pixel wide, and so is the gap already built
       into the right-hand side of every letter - so a space between words is
       exactly as wide as the join between two letters, and a sentence reads
       as onelongword. Three more pixels puts the word gap at four, which is
       about two thirds of the x-height and the usual place for it.

       It belongs here rather than in the font because the font is somebody
       else's and under a licence that would have us rename a modified copy;
       word-spacing costs one line and leaves the file untouched. */
    word-spacing: calc(3 * var(--fp));
}

/* --------------------------------------------------------------------- */
/* The page                                                               */
/*                                                                        */
/* Black, and the cabinet sits in the middle of it. The cabinet is only as */
/* tall as the menu bar plus the picture, so there is black above and      */
/* below as well as either side - which is the point. It should look like  */
/* a screen on a desk, not a web page that happens to contain a game.      */
/* --------------------------------------------------------------------- */

.quests-body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--ega-black);
    color: var(--ega-light-grey);
    overflow: hidden;
}

.quests-cabinet {
    display: flex;
    flex-direction: column;
    border: calc(1px * var(--t)) solid var(--ega-white);
    background: var(--ega-black);
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
}

/* --------------------------------------------------------------------- */
/* The menu bar                                                           */
/*                                                                        */
/* White, with black text, the way the SCI interpreter drew it. It is the  */
/* one part of the screen that is deliberately brighter than the game.     */
/* --------------------------------------------------------------------- */

/* It wraps. The cabinet's width belongs to the picture and the sidebars, and
 * on a narrow screen there are more buttons here than will fit across it. A
 * second row of menu bar is correct; a menu bar that shoves the cabinet wider
 * than the window is not. */
.quests-menubar {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: calc(1px * var(--t));
    padding: 0;
    border-bottom: calc(1px * var(--t)) solid var(--ega-white);
    background: var(--ega-white);
    color: var(--ega-black);
}

.quests-menubar-item {
    display: flex;
    align-items: center;
    padding: calc(3px * var(--t)) calc(5px * var(--t));
    white-space: nowrap;
    color: var(--ega-black);
    text-decoration: none;
}

.quests-menubar-title {
    text-transform: uppercase;
}

.quests-menubar-sep { color: var(--ega-dark-grey); }

.quests-menubar-spacer { flex: 1 1 auto; }

.quests-menubar-game {
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: calc(90px * var(--s));
    display: block;
    align-self: center;
}

.quests-menubar-who {
    color: var(--ega-dark-grey);
}

#quests-score { color: var(--ega-black); }

/* --------------------------------------------------------------------- */
/* Buttons                                                                */
/*                                                                        */
/* White with black text, a hard black border, and no hover colour wash -  */
/* they invert instead, which is what a bitmap UI did when it had no        */
/* spare colours to be subtle with.                                        */
/* --------------------------------------------------------------------- */

.quests-btn {
    display: inline-flex;
    align-items: center;
    padding: calc(3px * var(--t)) calc(5px * var(--t));
    border: calc(1px * var(--t)) solid var(--ega-black);
    background: var(--ega-white);
    color: var(--ega-black);
    font-family: var(--quests-font);
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
}

.quests-btn:hover,
.quests-btn:focus-visible {
    background: var(--ega-black);
    color: var(--ega-white);
    border-color: var(--ega-white);
    outline: none;
}

.quests-btn:active { background: var(--ega-dark-grey); color: var(--ega-white); }

/* In the menu bar the buttons have no border of their own - the bar is
 * already white, and a black box around every word turns it into a toolbar. */
.quests-menubar .quests-btn {
    border-color: transparent;
    padding: calc(3px * var(--t)) calc(4px * var(--t));
}

.quests-menubar .quests-btn:hover,
.quests-menubar .quests-btn:focus-visible {
    border-color: var(--ega-black);
    background: var(--ega-black);
    color: var(--ega-white);
}

/* Outside the menu bar - death screen, modals - the page behind is black,
 * so the button needs a white edge to sit on. */
.quests-death .quests-btn,
.quests-modal .quests-btn { border-color: var(--ega-white); }

.quests-btn-accent {
    background: var(--ega-yellow);
    color: var(--ega-black);
}

.quests-btn-accent:hover { background: var(--ega-black); color: var(--ega-yellow); }

/* --------------------------------------------------------------------- */
/* The three columns                                                      */
/*                                                                        */
/* Exactly as tall as the picture. The sidebars do not get to stretch the   */
/* cabinet: if there is more log than room, the log scrolls.                */
/* --------------------------------------------------------------------- */

/* overflow:hidden because the drawers park outside this box when they are
 * closed, and the page behind them is black rather than opaque - without it
 * a phone shows two slivers of sidebar sitting out in the dark either side
 * of the cabinet. */
/* Exactly as tall as the picture, and said rather than hoped for. A flex
   row is as tall as its tallest item, and a sidebar's height comes from its
   text, so a long history made the row taller instead of scrolling: the
   cabinet grew down the page and the picture grew with it. The engine
   writes --picture-h on every resize; with the height settled from outside,
   each panel is stretched to it and .quests-scroll finally has something to
   overflow. */
.quests-columns {
    position: relative;
    display: flex;
    align-items: stretch;
    height: var(--picture-h, auto);
    overflow: hidden;
}

.quests-stage {
    position: relative;
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    background: var(--ega-black);
}

.quests-canvas {
    image-rendering: pixelated;
    image-rendering: crisp-edges;           /* Firefox, older WebKit */
    -ms-interpolation-mode: nearest-neighbor;
    background: var(--ega-black);
    display: block;
}

/* --------------------------------------------------------------------- */
/* Side panels                                                            */
/*                                                                        */
/* Black, with a white rule between them and the picture. Dimmer than the  */
/* game on purpose: sixteen colours only looks bright next to something     */
/* that isn't competing with it.                                           */
/* --------------------------------------------------------------------- */

.quests-panel {
    display: flex;
    flex-direction: column;
    flex: 0 0 auto;
    width: calc(104px * var(--s));
    min-width: 0;
    background: var(--ega-black);
    color: var(--ega-light-grey);
}

.quests-drawer-left  { border-right: calc(1px * var(--t)) solid var(--ega-white); }
.quests-drawer-right { border-left:  calc(1px * var(--t)) solid var(--ega-white); }

.quests-panel-title {
    margin: 0;
    padding: calc(3px * var(--t)) calc(4px * var(--t));
    border-bottom: calc(1px * var(--t)) solid var(--ega-dark-grey);
    font-size: calc(16 * var(--fp));
    text-transform: uppercase;
    color: var(--ega-white);
}

.quests-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: calc(3px * var(--t)) calc(4px * var(--t));
    scrollbar-width: thin;
    scrollbar-color: var(--ega-dark-grey) transparent;
}

.quests-scroll::-webkit-scrollbar       { width: calc(4px * var(--t)); }
.quests-scroll::-webkit-scrollbar-thumb { background: var(--ega-dark-grey); }
.quests-scroll::-webkit-scrollbar-track { background: transparent; }

/* --------------------------------------------------------------------- */
/* The history log                                                        */
/*                                                                        */
/* Four voices told apart by colour alone, each one an EGA colour, so a    */
/* long scrollback still scans without labels.                             */
/* --------------------------------------------------------------------- */

.quests-log {
    margin: 0 0 calc(4px * var(--t));
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
    word-wrap: break-word;
}

.quests-log-narration { color: var(--ega-light-grey); }
.quests-log-speech    { color: var(--ega-white); }
.quests-log-action    { color: var(--ega-cyan); }

.quests-log-system {
    color: var(--ega-yellow);
    border-top: calc(1px * var(--t)) solid var(--ega-dark-grey);
    margin-top: calc(5px * var(--t));
    padding-top: calc(4px * var(--t));
}

/* --------------------------------------------------------------------- */
/* Inventory                                                              */
/* --------------------------------------------------------------------- */

.quests-inventory-empty {
    margin: 0;
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
    color: var(--ega-dark-grey);
}

.quests-item {
    display: flex;
    align-items: center;
    gap: calc(4px * var(--t));
    padding: calc(2px * var(--t));
    margin-bottom: calc(2px * var(--t));
    border: calc(1px * var(--t)) solid var(--ega-dark-grey);
    background: var(--ega-black);
    color: var(--ega-light-grey);
    cursor: grab;
    user-select: none;
}

.quests-item:hover  { border-color: var(--ega-white); color: var(--ega-white); }
.quests-item:active { cursor: grabbing; }

/* The icon is a game sprite, so it scales by the same rule the game does. */
.quests-item img {
    width: calc(16px * var(--s));
    height: calc(16px * var(--s));
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    flex-shrink: 0;
}

.quests-item > span:first-child {
    display: flex;
    width: calc(16px * var(--s));
    height: calc(16px * var(--s));
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    border: calc(1px * var(--t)) solid var(--ega-dark-grey);
    font-size: calc(16 * var(--fp));
    color: var(--ega-light-grey);
}

.quests-item-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: calc(16 * var(--fp));
}

/* --------------------------------------------------------------------- */
/* Status line                                                            */
/* --------------------------------------------------------------------- */

/* Centred rather than tucked along the bottom edge. It says "Loading…" over
 * a black screen, and the middle is where someone is already looking.
 *
 * The reason written here used to be that the hover label was along the
 * bottom. That label is gone - the cursor says what the mouse is over - so
 * the old reason outlived the thing it was about. The placement is still
 * right; it just needed a reason that is still true. */
.quests-status {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 10;
    padding: calc(2px * var(--t)) calc(4px * var(--t));
    border: calc(1px * var(--t)) solid var(--ega-white);
    background: var(--ega-black);
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
    color: var(--ega-white);
    pointer-events: none;
    white-space: nowrap;
}

.quests-status-error { color: var(--ega-red) !important; border-color: var(--ega-red); }

.hidden { display: none !important; }

/* There was a strip along the bottom of the picture naming whatever the
   mouse was over. It is gone, and so is the markup and the code behind it:
   the cursor is the whole interface, and a label answered the question
   before the player had asked it. */

/* --------------------------------------------------------------------- */
/* Speech over the canvas                                                 */
/*                                                                        */
/* Positioned over the speaker's head each frame. Narration sits at the    */
/* top of the scene, the way it did when the narrator was a disembodied    */
/* voice with opinions.                                                    */
/* --------------------------------------------------------------------- */

.quests-speech {
    position: absolute;
    z-index: 15;
    max-width: calc(200px * var(--s));
    padding: calc(2px * var(--t)) calc(4px * var(--t));
    border: calc(1px * var(--t)) solid var(--ega-white);
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
    text-align: center;
    transform: translate(-50%, -100%);
    cursor: pointer;
    user-select: none;
}

.quests-speech-character {
    background: var(--ega-black);
    color: var(--ega-white);
}

/* The narrator's box is the one piece of chrome a game may restyle, because it
   is the game talking rather than the cabinet. Width and border are in game
   pixels like everything else here; the colours come from the game's own
   sixteen, resolved to hex by the engine and written on the cabinet.

   Every property falls back to what it has always been, so a game that sets
   none of them is pixel for pixel the box it was before any of this existed -
   and quests.css stays the one place that appearance is written down. The
   border colour falls back to the text colour, which is what it has always
   done: set the text yellow and the box outlines itself to match. */
.quests-speech-narrator {
    max-width: calc(var(--narrator-w, 200) * 1px * var(--s));
    border-width: calc(var(--narrator-border, 1) * 1px * var(--t));
    background: var(--narrator-bg, var(--ega-black));
    color: var(--narrator-fg, var(--ega-yellow));   /* the EGA yellow narrators always used */
    border-color: var(--narrator-edge, var(--narrator-fg, var(--ega-yellow)));
    font-size: calc(var(--narrator-size, 16) * var(--fp));
    line-height: calc(var(--narrator-line, 13) * var(--fp));
    transform: translate(-50%, 0);
}

/* --------------------------------------------------------------------- */
/* Dialogue options                                                       */
/* --------------------------------------------------------------------- */

.quests-dialogue {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 25;
    display: flex;
    flex-direction: column;
    padding: calc(2px * var(--t));
    border-top: calc(1px * var(--t)) solid var(--ega-white);
    background: var(--ega-black);
}

.quests-dialogue-option {
    display: flex;
    gap: calc(4px * var(--t));
    width: 100%;
    padding: calc(2px * var(--t)) calc(4px * var(--t));
    border: calc(1px * var(--t)) solid transparent;
    background: transparent;
    font-family: var(--quests-font);
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
    text-align: left;
    color: var(--ega-cyan);
    cursor: pointer;
}

/* Inverted, not tinted. There is no half-highlight in a 16-colour UI. */
.quests-dialogue-option:hover,
.quests-dialogue-option:focus-visible {
    background: var(--ega-cyan);
    color: var(--ega-black);
    outline: none;
}

.quests-dialogue-number { flex-shrink: 0; }

/* --------------------------------------------------------------------- */
/* Save slots                                                             */
/* --------------------------------------------------------------------- */

.quests-modal {
    position: absolute;
    inset: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: calc(8px * var(--t));
    background: var(--ega-black);
}

.quests-modal-panel {
    width: 100%;
    max-width: calc(180px * var(--s));
    max-height: 100%;
    overflow-y: auto;
    padding: calc(6px * var(--t));
    border: calc(1px * var(--t)) solid var(--ega-white);
    background: var(--ega-black);
}

.quests-modal-title {
    margin: 0 0 calc(6px * var(--t));
    padding-bottom: calc(3px * var(--t));
    border-bottom: calc(1px * var(--t)) solid var(--ega-white);
    font-size: calc(16 * var(--fp));
    text-transform: uppercase;
    color: var(--ega-white);
}

.quests-slot-list {
    display: flex;
    flex-direction: column;
    margin-bottom: calc(6px * var(--t));
}

.quests-slot {
    display: flex;
    align-items: flex-start;
    gap: calc(4px * var(--t));
    padding: calc(3px * var(--t)) calc(4px * var(--t));
    border: calc(1px * var(--t)) solid transparent;
    background: transparent;
    font-family: var(--quests-font);
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
    text-align: left;
    color: var(--ega-light-grey);
    cursor: pointer;
}

.quests-slot:hover:not(:disabled),
.quests-slot:focus-visible:not(:disabled) {
    background: var(--ega-white);
    color: var(--ega-black);
    outline: none;
}

.quests-slot:disabled { color: var(--ega-dark-grey); cursor: not-allowed; }

.quests-slot-number { flex-shrink: 0; width: calc(10px * var(--t)); }

.quests-slot-empty { color: var(--ega-dark-grey); }
.quests-slot-when  { color: inherit; }

.quests-modal-cancel { width: 100%; justify-content: center; }

/* --------------------------------------------------------------------- */
/* Death                                                                  */
/*                                                                        */
/* It covers everything, on purpose. A Sierra death is supposed to stop    */
/* the room, not appear politely in a corner of it.                        */
/* --------------------------------------------------------------------- */

.quests-death {
    position: absolute;
    inset: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: calc(8px * var(--t));
    background: var(--ega-black);
}

.quests-death-panel {
    max-width: calc(260px * var(--s));
    padding: calc(8px * var(--t));
    border: calc(1px * var(--t)) solid var(--ega-red);
    background: var(--ega-black);
    text-align: center;
}

.quests-death-title {
    margin: 0 0 calc(6px * var(--t));
    font-size: calc(16 * var(--fp));
    text-transform: uppercase;
    color: var(--ega-red);
}

.quests-death-text {
    margin: 0 0 calc(8px * var(--t));
    font-size: calc(16 * var(--fp));
    line-height: calc(13 * var(--fp));
    color: var(--ega-light-grey);
}

.quests-death-buttons {
    display: flex;
    gap: calc(4px * var(--t));
    justify-content: center;
}

/* --------------------------------------------------------------------- */
/* Drawers                                                                */
/*                                                                        */
/* Below the three-column breakpoint the panels leave the flow and slide   */
/* in over the game, so the canvas keeps every pixel it can get. The       */
/* engine knows about this breakpoint too - QUESTS_DRAWER_WIDTH in         */
/* engine.js must stay in step with the media query below, or the cabinet  */
/* will be sized for sidebars that aren't there.                           */
/* --------------------------------------------------------------------- */

.quests-scrim {
    position: absolute;
    inset: 0;
    z-index: 20;
    background: var(--ega-black);
    opacity: 0.6;
}

/* The drawer buttons were the character U+2630, which Northrup has no glyph
   for - and a font that does would have drawn it smooth beside the pixel
   letters either side. Three bars are a shape, not a word, so they are drawn
   here instead: each one exactly one font pixel thick, on the same grid as
   everything else, and in currentColor so the button's own states carry it. */
.quests-drawer-toggle { display: none; }

.quests-drawer-toggle::before {
    content: "";
    display: block;
    width: calc(9 * var(--fp));
    height: calc(5 * var(--fp));
    background-image: linear-gradient(currentColor, currentColor),
                      linear-gradient(currentColor, currentColor),
                      linear-gradient(currentColor, currentColor);
    background-size: 100% var(--fp);
    background-repeat: no-repeat;
    background-position: 0 0, 0 calc(2 * var(--fp)), 0 calc(4 * var(--fp));
}

@media (max-width: 1023px) {
    .quests-drawer-toggle { display: inline-flex; }
}

@media (max-width: 1023px) {
    .quests-panel {
        position: absolute;
        top: 0;
        bottom: 0;
        z-index: 30;
        width: calc(104px * var(--s));
        max-width: 80%;
        transition: transform 0.18s steps(4, end);
    }

    .quests-drawer-left  { left: 0;  transform: translateX(-100%); }
    .quests-drawer-right { right: 0; transform: translateX(100%); }

    .quests-drawer-left.quests-drawer-open,
    .quests-drawer-right.quests-drawer-open { transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
    .quests-panel { transition: none; }
}

/* --------------------------------------------------------------------- */
/* Score pulse                                                            */
/*                                                                        */
/* Steps, not a fade. Nothing in a 16-colour UI tweens.                    */
/* --------------------------------------------------------------------- */

@keyframes quests-score-flash {
    0%, 100% { color: inherit; }
    25%, 75% { color: var(--ega-white); background: var(--ega-black); }
}

.quests-score-flash {
    display: inline-block;
    animation: quests-score-flash 0.6s steps(1, end) 2;
}

@media (prefers-reduced-motion: reduce) {
    .quests-score-flash { animation: none; }
}
