/* -------------------------------------------------------------------------
   -hyphenate popup — menu, POS, order tracker, pay screen.
   Same Atom One Light palette and Menlo mono as the concept site; the only
   departure is bigger hit targets on admin, because thumbs are not cursors.
   ------------------------------------------------------------------------- */

:root {
    --color-blue:   #4078f2;
    --color-red:    #e45649;
    --color-green:  #50a14f;
    --color-purple: #a626a4;
    --color-orange: #c18401;
    --color-cyan:   #0997b3;
    --color-fg:     #383a42;
    --color-bg:     #fafafa;
    --color-muted:  #6b7280;   /* was #9199a6 — 2.75:1 on the page ground, under
                                  the 4.5:1 AA floor, while carrying the sync strip,
                                  timestamps and captions. #6b7280 is ~4.8:1. */
    --color-rule:   #e3e5e9;
}

/* -------------------------------------------------------------------------
   WHAT THE COLOURS MEAN — one job each.

     fg      everything you read
     muted   everything secondary
     green   money, and only money
     red     something needs attention
     blue    links, and only links
     cyan    a person's own words — chat, notes, order modifiers
     purple  who is speaking
     orange  a special request

   The palette is Atom One Light, which is a syntax-highlighting theme: these
   colours originally meant "string" and "keyword", not anything about an
   interface. Every one of them will happily take a second job if you let it —
   that is how green ended up meaning both a price and a healthy connection.
   Before colouring something new, check the list above first.
   ------------------------------------------------------------------------- */

* { box-sizing: border-box; }

body {
    font-family: 'Menlo', 'Menlo', monospace;
    font-size: small;
    color: var(--color-fg);
    background: var(--color-bg);
    margin: 0;
    padding: 1.5em 1em 4em;
    line-height: 1.5;
    -webkit-text-size-adjust: 100%;
}

.wrap {
    max-width: 34em;
    margin: 0 auto;
}

.wrap-wide { max-width: 52em; }

a { color: var(--color-blue); }

h1, h2, h3 {
    font-size: small;
    font-weight: 600;
    margin: 0;
}

hr {
    border: 0;
    border-top: 1px solid var(--color-rule);
    margin: 1.25em 0;
}

.muted { color: var(--color-muted); }
.small { font-size: 11px; }
.right { text-align: right; }
.center { text-align: center; }
.stack > * + * { margin-top: 0.5em; }
.row { display: flex; gap: 0.5em; align-items: center; }
.row-between { display: flex; gap: 0.5em; align-items: center; justify-content: space-between; }
.grow { flex: 1; min-width: 0; }
.nowrap { white-space: nowrap; }

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

.masthead {
    text-align: center;
    margin-bottom: 1.5em;
}

.masthead .mark {
    letter-spacing: 0.04em;
}

.masthead .tag {
    color: var(--color-muted);
    font-style: italic;
}

/* On the guest pages the title links home.

   No min-height here, deliberately. A 44px tap target on a 20px line leaves
   surplus height that pushes the tagline down and reads as a blank line —
   which is exactly the bug this replaced. The link has to measure the same
   as the plain masthead it stands in for, so it takes the height of its own
   text and nothing more. This is a secondary way home rather than a primary
   action, and the cost of missing it is a tap on your own site's title.

   admin.html keeps a plain, unlinked masthead — the register shouldn't have
   a one-tap exit sitting at the top of it mid-order. */
a.mark {
    display: block;
    width: fit-content;      /* the words are the target, not the whitespace */
    margin: 0 auto;
    color: inherit;          /* stays a masthead, not a blue link */
    text-decoration: none;
    touch-action: manipulation;
    -webkit-tap-highlight-color: rgba(64, 120, 242, 0.15);
}

/* Hover stays behind a real pointer — iOS applies it on tap and then keeps it
   until you touch something else. :active is what a thumb actually gets. */
@media (hover: hover) {
    a.mark:hover { color: var(--color-blue); }
}

a.mark:active { color: var(--color-blue); }

a.mark:focus-visible {
    outline: 1px solid var(--color-blue);
    outline-offset: 2px;
}

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

button {
    font-family: inherit;
    font-size: small;
    color: inherit;
    background: none;
    border: 1px solid var(--color-rule);
    padding: 0.5em 0.85em;
    cursor: pointer;
    border-radius: 2px;
    line-height: 1.3;
}

button:hover:not(:disabled) { border-color: var(--color-fg); }
button:disabled { opacity: 0.35; cursor: default; }

button.primary {
    border-color: var(--color-fg);
    background: var(--color-fg);
    color: var(--color-bg);
}

button.danger { color: var(--color-red); border-color: var(--color-rule); }
button.danger:hover:not(:disabled) { border-color: var(--color-red); }
button.ghost { border-color: transparent; padding: 0.25em 0.4em; }
button.ghost:hover:not(:disabled) { border-color: var(--color-rule); }
button.tiny { padding: 0.15em 0.45em; font-size: 11px; }

/* -------------------------------------------------------------------------
   THE TYPE SCALE — three sizes, and each one means something.

     16px  you type in it     form fields, the buttons sitting among them,
                               and the close-up (the enlarged figure in a
                               guest's sheet — used to be its own 20px size,
                               dropped for feeling larger than it needed to)
     13px  you read it        the base: body, buttons, names, prices, messages
     11px  you glance at it   time, sync status, form hints, badges, captions

   Anything that needs to be bigger or smaller than its neighbours almost
   always wants padding, weight or colour instead — reach for those before
   adding a fourth size.
   ------------------------------------------------------------------------- */

input, select, textarea {
    font-family: inherit;
    /* 16px, not "small" (~13px) — iOS Safari auto-zooms the whole page on
       focus of any text field under 16px, which gets old fast on a POS
       used all day on an iPad. */
    font-size: 16px;
    color: inherit;
    background: var(--color-bg);
    border: 1px solid var(--color-rule);
    padding: 0.45em 0.55em;
    border-radius: 2px;
    width: 100%;
}

input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--color-blue);
}

label.field { display: block; }
label.field > span { display: block; color: var(--color-muted); font-size: 11px; }

/* --- public menu --------------------------------------------------------- */

.menu-section + .menu-section { margin-top: 1.75em; }

.menu-section > h2 {
    color: var(--color-fg);
    margin-bottom: 0.6em;
}
.menu-section > h2::before { content: '♥ '; color: var(--color-fg); }

.menu-item + .menu-item { margin-top: 0.9em; }

.menu-item .line {
    display: flex;
    align-items: baseline;
    gap: 0.5em;
}

.menu-item .leader {
    flex: 1;
    border-bottom: 1px dotted var(--color-rule);
    transform: translateY(-0.25em);
}

.menu-item .price { color: var(--color-green); }
.menu-item .description {
    color: var(--color-muted);
    /* Keeps a wrapped line from running out to the same right edge the
       price sits flush against above it — without this a line break could
       land directly under the price's $, reading as if it belonged to it. */
    margin-right: 3em;
}

.menu-item.sold-out .name,
.menu-item.sold-out .price { text-decoration: line-through; }
.menu-item.sold-out { opacity: 0.55; }

.badge {
    display: inline-block;
    font-size: 11px;
    border: 1px solid var(--color-rule);
    border-radius: 2px;
    padding: 0 0.35em;
    color: var(--color-muted);
    white-space: nowrap;
}

/* --- tabs ---------------------------------------------------------------- */

.tabs {
    display: flex;
    gap: 0.25em;
    border-bottom: 1px solid var(--color-rule);
    margin-bottom: 1.25em;
    overflow-x: auto;
}

.tabs button {
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    padding: 0.5em 0.75em;
    color: var(--color-muted);
    white-space: nowrap;
}
.tabs button[aria-selected='true'] {
    color: var(--color-fg);
    border-bottom-color: var(--color-fg);
}

/* --- POS ----------------------------------------------------------------- */

.pos-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(9.5em, 1fr));
    gap: 0.4em;
    margin-bottom: 0.5em;
}

.pos-tile {
    text-align: left;
    padding: 0.6em;
    min-height: 4.25em;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 0.3em;
}
.pos-tile .t-name { line-height: 1.25; }
.pos-tile .t-price { color: var(--color-green); }   /* base — a price reads the same here as on the menu */
.pos-tile[data-sold-out='true'] { opacity: 0.4; }

.cart-line { padding: 0.5em 0; border-top: 1px dotted var(--color-rule); }
.cart-line .mods { color: var(--color-cyan); font-size: 11px; }
.cart-line .lnote { color: var(--color-orange); font-size: 11px; font-style: italic; }

.qty { display: inline-flex; align-items: center; gap: 0.35em; }
.qty button { width: 2em; padding: 0.15em 0; text-align: center; }

.totals { border-top: 1px solid var(--color-fg); padding-top: 0.5em; margin-top: 0.5em; }
.totals .grand { font-weight: 600; }

/* --- order tracker ------------------------------------------------------- */

.ticket {
    border: 1px solid var(--color-rule);
    border-left: 3px solid var(--color-rule);
    border-radius: 2px;
    padding: 0.6em 0.75em;
    margin-bottom: 0.5em;
}
.ticket[data-status='queued'] { border-left-color: var(--color-orange); }
.ticket[data-status='ready']  { border-left-color: var(--color-green); }
.ticket[data-status='done']   { border-left-color: var(--color-rule); opacity: 0.6; }
/* .ticket .num is deliberately uncoloured — it inherits ink. The leading "#"
   already marks it as an order number, and purple now means "who is speaking". */
.ticket .who { font-weight: 600; }
.ticket ul { margin: 0.4em 0; padding-left: 1.1em; }
.ticket li { margin: 0.15em 0; }
.ticket .unpaid { color: var(--color-red); }
.ticket .paid { color: var(--color-green); }

.stale { color: var(--color-red); }

/* --- modal --------------------------------------------------------------- */

.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(56, 58, 66, 0.35);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1em;
    z-index: 10;
}

.modal {
    background: var(--color-bg);
    border: 1px solid var(--color-fg);
    border-radius: 2px;
    padding: 1em;
    max-width: 26em;
    width: 100%;
    max-height: 85vh;
    overflow-y: auto;
}

/* --- QR / pay ------------------------------------------------------------ */

.qr {
    display: inline-block;
    padding: 0.75em;
    background: #fff;
    border: 1px solid var(--color-rule);
    line-height: 0;
}
.qr svg { display: block; width: 100%; height: auto; max-width: 15em; }

/* Belongs to the payment-confirmation screen that is commented out in pos.js,
   so this never renders. Left with the rest of that feature rather than
   deleted — but note it was the largest size in the file, which made the
   scale look wider than it really is.

.amount-due {
    font-size: 2.25em;
    line-height: 1.1;
    color: var(--color-green);
}
*/

.mod-toggle {
    display: inline-block;
    border: 1px solid var(--color-rule);
    border-radius: 2px;
    padding: 0.35em 0.6em;
    cursor: pointer;
    margin: 0 0.3em 0.3em 0;
}
.mod-toggle input { width: auto; margin-right: 0.4em; }
.mod-toggle:has(input:checked) { border-color: var(--color-fg); }

/* --- status strip -------------------------------------------------------- */

.status-strip {
    font-size: 11px;
    color: var(--color-muted);
    text-align: center;
    margin-bottom: 1em;
}
/* The dot only shouts when something is actually wrong. "synced live" and
   "this device only" both read muted — the label beside the dot already
   spells out which — so green stays money and orange stays a request. */
.status-strip .dot { color: var(--color-muted); }
.status-strip .dot.degraded { color: var(--color-red); }

table.report { width: 100%; border-collapse: collapse; }
table.report th, table.report td {
    text-align: left;
    padding: 0.3em 0.5em 0.3em 0;
    border-bottom: 1px dotted var(--color-rule);
}
table.report td.n, table.report th.n { text-align: right; }

@media print {
    body { padding: 0; }
    .no-print { display: none !important; }
}

/* --- check in / the room -------------------------------------------------- */

.door { max-width: 18em; margin: 3em auto; }

/* Poses are <pre>, so the block centres as a unit while the text inside stays
   left-aligned. That matters: the waving figure raises its arm by shifting the
   face one column, and centring each line on its own would undo it. */
.g-pose {
    display: inline-block;
    margin: 0;
    text-align: left;
    font-family: inherit;
    line-height: 1.2;
    white-space: pre;
}
.g-pose.big { font-size: 16px; }

.g-emoji { line-height: 1.2; min-height: 1.2em; }
.g-emoji.big { font-size: 16px; }

/* --- picking an activity -------------------------------------------------- */

.activity-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8.5em, 1fr));
    gap: 0.4em;
}

.activity-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 0.35em;
    padding: 0.7em 0.4em;
    min-height: 6em;
    text-align: center;
}
.activity-tile .a-label { line-height: 1.3; }   /* base — it is the button's label */
.activity-tile[aria-pressed='true'] { border-color: var(--color-fg); }

/* --- flair ---------------------------------------------------------------- */

.emoji-row { display: flex; flex-wrap: wrap; gap: 0.3em; margin-top: 0.25em; }

.emoji-opt {
    width: 2.4em;
    height: 2.4em;
    padding: 0;
    text-align: center;
    font-size: 16px;   /* matches the name field above it, not a size of its own */
    line-height: 1;
}
.emoji-opt[aria-pressed='true'] { border-color: var(--color-fg); background: var(--color-rule); }

/* --- the room ------------------------------------------------------------- */

/* Pulled out past the body's 1em side padding so the ceiling and floor meet
   the edges of the screen. Deliberately -1em rather than a 100vw full-bleed:
   vw units include the scrollbar, which is exactly how a page ends up with a
   horizontal scrollbar it didn't ask for. This cancels a known padding
   instead, so it can't overshoot. The long tiled lines inside overflow this
   box and are clipped by the rule below — that's what fills the width. */
.room-banner, .room-floor {
    margin: 0 -1em;
    text-align: center;
    color: var(--color-muted);
    font-family: inherit;
    line-height: 1.2;
    overflow: hidden;
}
.room-banner { margin-bottom: 0.75em; }
.room-floor { margin-top: 0.25em; margin-bottom: 0.75em; color: var(--color-fg); }

.room-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8em, 1fr));
    gap: 0.5em 0.3em;
    align-items: end;
}

.guest {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    gap: 0.15em;
    padding: 0.5em 0.3em;
    min-height: 7em;
    border-color: transparent;
    text-align: center;
}
.guest:hover:not(:disabled) { border-color: var(--color-rule); }
.guest[data-me='true'] { border-color: var(--color-rule); background: rgba(64, 120, 242, 0.05); }
.guest[data-stale='true'] { opacity: 0.45; }

/* Two lines reserved, for the same reason .g-act reserves two: at the base
   size a longer name wraps, and because cells are bottom-aligned that lifts
   one figure above the row and the floor stops reading as a floor. */
.guest .g-name {                    /* base — the most important text in the room */
    line-height: 1.25;
    min-height: 2.5em;
    overflow-wrap: anywhere;
}
/* Deliberately not blue: blue is the link colour everywhere else, and colouring
   a name with it suggests the name is clickable when the whole cell is. Your
   own cell already announces itself with a border, a tinted fill and "(you)". */
/* Same two-line reservation as .g-name above, and for the same reason. */
.guest .g-act {
    font-size: 11px;
    line-height: 1.2;
    min-height: 2.4em;
    overflow-wrap: anywhere;
}

/* The note rides above the figure like a little speech bubble. Clamped to two
   lines so one chatty guest can't stretch every cell in their row. */
.guest .g-note {
    line-height: 1.25;
    color: var(--color-cyan);
    border: 1px solid var(--color-rule);
    border-radius: 2px;
    padding: 0.15em 0.3em;
    margin-bottom: 0.15em;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}

.guest.preview { border-color: var(--color-rule); min-height: 0; display: inline-flex; }

/* --- the guest sheet ------------------------------------------------------ */

.g-said { color: var(--color-cyan); font-style: italic; overflow-wrap: anywhere; }

.sheet-actions { display: flex; flex-direction: column; gap: 0.4em; }
.sheet-actions button { width: 100%; }

/* --- what's happening ----------------------------------------------------- */

.log-line { line-height: 1.4; overflow-wrap: anywhere; }
.log-line .who { color: var(--color-purple); }
.log-line .said { color: var(--color-cyan); }

/* The composer sits above the log, with the newest message directly beneath
   it. align-items:stretch so the button matches the input's height rather
   than the two disagreeing by a pixel at 16px type. */
.composer {
    display: flex;
    align-items: stretch;
    gap: 0.4em;
    margin-top: 0.75em;
}
.composer .say-input { flex: 1; min-width: 0; }
.composer button { white-space: nowrap; }
