/* ==========================================================================
   ROSFlow — Design System
   Matte black · graphite · champagne gold · warm white
   Every value here is a token. Nothing in a view hardcodes a colour.
   ========================================================================== */

:root {
  /* ---- surface ladder: each step is a real material, not just a shade ---- */
  --ink-900:  #06060700;      /* void (used behind blurs) */
  --ink-950:  #070708;        /* matte black — the stage */
  --ink-900s: #0B0B0D;        /* page */
  --ink-850:  #101012;        /* raised panel */
  --ink-800:  #16161A;        /* card */
  --ink-750:  #1C1C21;        /* card hover */
  --ink-700:  #24242B;        /* graphite — inputs, wells */
  --ink-600:  #32323B;        /* hairline strong */
  --ink-500:  #4A4A55;        /* disabled ink */

  /* ---- ink on dark ---- */
  --warm-100: #F7F3EA;        /* warm white — primary text */
  --warm-300: #D9D3C6;        /* secondary */
  --warm-500: #9C968A;        /* tertiary / labels */
  --warm-700: #6A6560;        /* quaternary */

  /* ---- accent: champagne ---- */
  --gold-100: #F6EBD2;
  --gold-300: #EAD6A8;
  --gold-400: #D8BE86;        /* THE accent */
  --gold-500: #C2A66C;
  --gold-700: #8A7444;
  --gold-900: #3A3020;

  /* ---- semantic accents (muted, never loud) ---- */
  --mint-400: #7FBBA3;  --mint-900: #16281F;
  --rose-400: #C97F7F;  --rose-900: #2B1A1A;
  --amber-400:#D3A55F;  --amber-900:#2C2113;
  --royal-400:#7E9BC4;  --royal-900:#1A2130;
  --slate-400:#8A8A96;  --slate-900:#1E1E24;

  /* ---- brand hooks (overridden per tenant at runtime) ---- */
  --accent:      var(--gold-400);
  --accent-soft: var(--gold-300);

  /* ---- lines ---- */
  --line:        rgba(247, 243, 234, .07);
  --line-strong: rgba(247, 243, 234, .13);
  --line-gold:   rgba(216, 190, 134, .22);

  /* ---- elevation: long, soft, low-opacity. Luxury never casts a hard shadow ---- */
  --sh-1: 0 1px 2px rgba(0,0,0,.4), 0 2px 8px rgba(0,0,0,.24);
  --sh-2: 0 2px 4px rgba(0,0,0,.34), 0 12px 32px -8px rgba(0,0,0,.55);
  --sh-3: 0 4px 8px rgba(0,0,0,.3), 0 32px 64px -16px rgba(0,0,0,.7);
  --sh-gold: 0 0 0 1px var(--line-gold), 0 8px 32px -12px rgba(216,190,134,.28);

  /* The landing nav once it lifts off the hero. A token rather than a literal,
     because the one time it was a literal it stayed dark when the lights came
     up and nothing else in the file was wrong. */
  --nav-stuck: rgba(16, 16, 18, .72);

  /* ---- radii ---- */
  /* Softened one step across the board. Buttons and inputs at 10px read as
     utilitarian; at 14px they read as considered. Shared by both themes —
     parity means geometry is identical and only the light differs. */
  --r-sm: 14px; --r-md: 18px; --r-lg: 22px; --r-xl: 28px; --r-2xl: 36px;

  /* ---- motion: one curve for entrances, one for exits ---- */
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --t-fast: 160ms; --t-base: 280ms; --t-slow: 520ms;

  /* ---- type ---- */
  --serif: 'Cormorant Garamond', 'Iowan Old Style', Georgia, serif;
  --sans:  'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --mono:  'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --nav-w: 264px;
  --topbar-h: 68px;
}

/* ==========================================================================
   Base
   ========================================================================== */

* { -webkit-tap-highlight-color: transparent; }

html { scroll-behavior: smooth; }

body {
  background: var(--ink-950);
  color: var(--warm-100);
  font-family: var(--sans);
  font-feature-settings: 'cv02','cv03','cv04','ss01';
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  letter-spacing: -0.011em;
  overflow-x: hidden;
}

/* The stage: an almost-invisible warm halo so matte black never reads as flat. */
body::before {
  content: '';
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(120% 80% at 50% -20%, rgba(216,190,134,.055), transparent 60%),
    radial-gradient(80% 60% at 100% 100%, rgba(126,155,196,.035), transparent 60%);
}

/* Film grain — the single most effective way to make dark UI feel like material. */
body::after {
  content: '';
  position: fixed; inset: 0; z-index: 1; pointer-events: none; opacity: .028;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.stage { position: relative; z-index: 2; }

h1,h2,h3,.serif { font-family: var(--serif); font-weight: 300; letter-spacing: -0.015em; }
.serif-med { font-family: var(--serif); font-weight: 500; }

/* Display type: large, airy, optically loose. */
.display   { font-family: var(--serif); font-weight: 300; line-height: .96; letter-spacing: -0.03em; }
.eyebrow   { font-size: .625rem; letter-spacing: .22em; text-transform: uppercase; color: var(--warm-500); font-weight: 500; }
.eyebrow-gold { color: var(--accent); }
.num       { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum','ss01'; }
.mono      { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* Hairline gold rule used as a section divider. */
.rule-gold {
  height: 1px; border: 0;
  background: linear-gradient(90deg, transparent, var(--line-gold) 18%, var(--line-gold) 82%, transparent);
}

::selection { background: rgba(216,190,134,.28); color: var(--warm-100); }

/* ==========================================================================
   Scrollbars — thin, gold on hover
   ========================================================================== */
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--ink-700); border-radius: 99px; border: 2px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-thumb:hover { background: var(--gold-700); background-clip: padding-box; }
.no-bar::-webkit-scrollbar { display: none; }
.no-bar { scrollbar-width: none; }

/* ==========================================================================
   Surfaces
   ========================================================================== */

.card {
  background: linear-gradient(160deg, var(--ink-800), var(--ink-850) 70%);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  transition: border-color var(--t-base) var(--ease-out),
              box-shadow var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out);
}
.card-hover:hover { border-color: var(--line-strong); box-shadow: var(--sh-2); transform: translateY(-2px); }
.card-gold { border-color: var(--line-gold); box-shadow: var(--sh-gold); }

/* Glass — reserved for floating chrome only (nav bars, sheets, overlays). */
.glass {
  background: rgba(16,16,18,.72);
  backdrop-filter: blur(24px) saturate(140%);
  -webkit-backdrop-filter: blur(24px) saturate(140%);
  border: 1px solid var(--line-strong);
}
.glass-deep {
  background: rgba(7,7,8,.86);
  backdrop-filter: blur(32px) saturate(120%);
  -webkit-backdrop-filter: blur(32px) saturate(120%);
}

.well { background: var(--ink-950); border: 1px solid var(--line); border-radius: var(--r-md); }

/* A well that is also a control.
 *
 * There is no font-inherit reset in this sheet, so a tile that becomes a
 * <button> silently drops to the browser's UI font and stops looking like the
 * two tiles beside it. The hover is deliberately quieter than .card-hover: this
 * is a figure that can be opened, not a card asking to be clicked. */
.well-action {
  font: inherit; color: inherit; text-align: left; width: 100%; cursor: pointer;
  transition: border-color var(--t-base) var(--ease-out),
              background var(--t-base) var(--ease-out);
}
.well-action:hover { border-color: var(--line-strong); background: var(--ink-900); }

/* Raw data shown to a person: a sync payload, a captured message. Keeps its
 * line breaks and still wraps, so a long identifier cannot push a card wider
 * than the column it sits in. */
.pre-wrap { white-space: pre-wrap; overflow-wrap: anywhere; }

/* Top-lit edge: a 1px highlight along the top of a card, like brushed metal. */
.lit { position: relative; }
.lit::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 1px; border-radius: inherit;
  background: linear-gradient(90deg, transparent, rgba(247,243,234,.14) 30%, rgba(247,243,234,.14) 70%, transparent);
}

/* ==========================================================================
   Tone system — one class drives dot, text, border and wash
   ========================================================================== */

.tone-gold  { --tone: var(--gold-400);  --tone-bg: rgba(216,190,134,.09); --tone-br: rgba(216,190,134,.24); }
.tone-mint  { --tone: var(--mint-400);  --tone-bg: rgba(127,187,163,.09); --tone-br: rgba(127,187,163,.24); }
.tone-rose  { --tone: var(--rose-400);  --tone-bg: rgba(201,127,127,.10); --tone-br: rgba(201,127,127,.26); }
.tone-amber { --tone: var(--amber-400); --tone-bg: rgba(211,165,95,.09);  --tone-br: rgba(211,165,95,.24); }
.tone-royal { --tone: var(--royal-400); --tone-bg: rgba(126,155,196,.10); --tone-br: rgba(126,155,196,.24); }
.tone-slate { --tone: var(--slate-400); --tone-bg: rgba(138,138,150,.09); --tone-br: rgba(138,138,150,.20); }

.pill {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .28rem .62rem; border-radius: 99px;
  font-size: .6875rem; font-weight: 500; letter-spacing: .02em;
  background: var(--tone-bg); border: 1px solid var(--tone-br); color: var(--tone);
  white-space: nowrap;
}
.pill-dot::before {
  content: ''; width: 5px; height: 5px; border-radius: 99px; background: var(--tone);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--tone) 18%, transparent);
}
.pill-lg { padding: .42rem .85rem; font-size: .75rem; }

/* Live pulse for anything ticking in real time. */
.pulse::before { animation: pulse 2.4s var(--ease-in-out) infinite; }
@keyframes pulse {
  0%,100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--tone) 40%, transparent); }
  50%     { box-shadow: 0 0 0 6px color-mix(in srgb, var(--tone) 0%, transparent); }
}

/* ==========================================================================
   Controls
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  height: 42px; padding: 0 1.15rem; border-radius: var(--r-sm);
  font-size: .8125rem; font-weight: 500; letter-spacing: .01em;
  border: 1px solid transparent; cursor: pointer; user-select: none;
  transition: all var(--t-fast) var(--ease-out);
}
.btn:active { transform: scale(.975); }

.btn-gold {
  background: linear-gradient(180deg, var(--gold-300), var(--gold-500));
  color: #17130A; font-weight: 600;
  box-shadow: 0 1px 0 rgba(255,255,255,.35) inset, 0 6px 20px -8px rgba(216,190,134,.6);
}
.btn-gold:hover { background: linear-gradient(180deg, var(--gold-100), var(--gold-400)); box-shadow: 0 1px 0 rgba(255,255,255,.45) inset, 0 10px 28px -8px rgba(216,190,134,.75); }

.btn-ghost { background: rgba(247,243,234,.04); border-color: var(--line-strong); color: var(--warm-300); }
.btn-ghost:hover { background: rgba(247,243,234,.08); color: var(--warm-100); border-color: var(--line-gold); }

.btn-quiet { background: transparent; color: var(--warm-500); }
.btn-quiet:hover { color: var(--warm-100); background: rgba(247,243,234,.05); }

.btn-danger { background: rgba(201,127,127,.12); border-color: rgba(201,127,127,.3); color: var(--rose-400); }
.btn-danger:hover { background: rgba(201,127,127,.2); }

.btn-sm { height: 34px; padding: 0 .8rem; font-size: .75rem; }
.btn-lg { height: 52px; padding: 0 1.6rem; font-size: .875rem; border-radius: var(--r-md); }
.btn-block { width: 100%; }

/* The element selector is deliberate and load-bearing.
 *
 * In CDN mode Tailwind is loaded with ?plugins=forms, whose preflight styles
 * [type='search'], [type='email'], [type='number'] and the rest with a white
 * background and a grey border — and the CDN injects its stylesheet at runtime,
 * after this file, so at equal specificity it won. Every input carrying an
 * explicit type attribute rendered white with warm-white text on it: 127 of
 * them, including both fields on the sign-in screen, where each character typed
 * was invisible.
 *
 * `input.input` is 0,1,1 and beats `[type='search']` at 0,1,0 whatever the
 * order. The plugin has also been dropped from the CDN URL — nothing here used
 * it — but this stands on its own, because a specificity bug fixed only by
 * removing the thing that triggered it comes back with the next plugin. */
.input,
input.input,
select.input,
textarea.input {
  width: 100%; height: 44px; padding: 0 .9rem;
  background: var(--ink-950); border: 1px solid var(--line-strong);
  border-radius: var(--r-sm); color: var(--warm-100); font-size: .875rem;
  transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
  /* Chrome paints a UA background on search and date inputs from the
     colour-scheme, not from any rule. Naming the scheme is what stops it. */
  color-scheme: dark;
}
:root[data-skin="light"] .input,
:root[data-skin="light"] input.input,
:root[data-skin="light"] select.input,
:root[data-skin="light"] textarea.input { color-scheme: light; }

.input::placeholder, input.input::placeholder, textarea.input::placeholder {
  color: var(--warm-700);
}

/* The clear cross Chrome draws inside a search field is black on black. */
.input::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none;
  width: 14px; height: 14px; cursor: pointer; opacity: .5;
  background: var(--warm-500);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 6 6 18M6 6l12 12' stroke='%23000' stroke-width='2.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") center/contain no-repeat;
}
.input::-webkit-search-cancel-button:hover { opacity: 1; }
.input:focus { outline: none; border-color: var(--line-gold); box-shadow: 0 0 0 3px rgba(216,190,134,.1); }

/* Focus ring — visible, gold, never removed. */
:where(a,button,input,select,textarea,[tabindex]):focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px;
}

/* Segmented control */
.seg { display: inline-flex; padding: 3px; background: var(--ink-950); border: 1px solid var(--line); border-radius: var(--r-sm); gap: 2px; }
/* The border is transparent on every segment, not absent, so selecting one
   does not shift the others by two pixels. */
.seg > button,
.seg > a {
  padding: .42rem .85rem; border-radius: 8px; font-size: .75rem; font-weight: 500;
  border: 1px solid transparent;
  color: var(--warm-500); transition: all var(--t-fast) var(--ease-out); white-space: nowrap;
}

/* The selected segment was `background: var(--ink-750)` and nothing else.
   In the night skin that is #1C1C21 on a #070708 rail — a real lift. In the day
   skin it is **#F8F5EF on #FAF7F2**: three points of blue and two of everything
   else, which is no difference at all. Anybody on the light theme could not see
   which of Monthly and Annual was chosen, on the one control that decides what
   price the whole table shows.
   
   Every other selected state in this file says gold — `.chip`, `.chip-on`, the
   switch. This one was the exception for no reason, so it says gold too: a gold
   rule and a lifted surface, legible in both skins without shouting like a
   filled chip would on a billing toggle. */
.seg > button[aria-selected="true"],
.seg > a[aria-selected="true"] {
  background: var(--ink-700);
  border-color: var(--line-gold);
  color: var(--warm-100);
  box-shadow: var(--sh-1);
}
.seg > button:hover,
.seg > a:hover { color: var(--warm-100); }

/* Keyboard users had nothing at all: no focus ring, and a selected state they
   could not see either. */
.seg > button:focus-visible,
.seg > a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Switch */
.switch { position: relative; width: 44px; height: 25px; flex: none; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.switch i {
  position: absolute; inset: 0; border-radius: 99px; background: var(--ink-700);
  border: 1px solid var(--line-strong); transition: all var(--t-base) var(--ease-out);
}
.switch i::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 17px; height: 17px;
  border-radius: 99px; background: var(--warm-500); transition: all var(--t-base) var(--ease-out);
}
.switch input:checked + i { background: linear-gradient(180deg, var(--gold-500), var(--gold-700)); border-color: var(--line-gold); }
.switch input:checked + i::after { left: 22px; background: var(--gold-100); }
.switch input:focus-visible + i { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ==========================================================================
   Navigation
   ========================================================================== */

.nav-item {
  display: flex; align-items: center; gap: .7rem;
  padding: .58rem .7rem; border-radius: var(--r-sm);
  font-size: .8125rem; color: var(--warm-500); font-weight: 450;
  transition: all var(--t-fast) var(--ease-out); position: relative;
}
.nav-item:hover { background: rgba(247,243,234,.045); color: var(--warm-100); }
/* The screen you are on.
 *
 * This existed at 8% opacity with a 2px marker, which is legible only if you
 * already know where to look — and on a rail of eighteen items, "which one am I
 * on" is the question the nav is answering. Now the fill carries a gold edge,
 * the label is at full weight, and the marker is a 3px champagne rule that runs
 * most of the item's height. Still quiet; no longer a guess. */
.nav-item[aria-current="page"] {
  background: rgba(216,190,134,.13);
  color: var(--gold-100);
  font-weight: 550;
  box-shadow: inset 0 0 0 1px var(--line-gold);
}
.nav-item[aria-current="page"] svg { opacity: 1; color: var(--accent); }
.nav-item[aria-current="page"]::before {
  content: ''; position: absolute; left: -9px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 60%; border-radius: 3px; background: var(--accent);
  box-shadow: 0 0 10px -1px var(--accent);
}
.nav-item svg { width: 17px; height: 17px; flex: none; opacity: .85; }

/* --------------------------------------------------------------------------
   Collapsible rail
   The whole layout is driven by --nav-w, so collapsing is one token change:
   the rail narrows and <main>'s margin follows it. Labels hide, icons centre,
   and a tooltip carries the name that the label used to.
   -------------------------------------------------------------------------- */

:root[data-nav="mini"] { --nav-w: 76px; }

/* Only the fixed desktop rail collapses. The mobile drawer is already an
   overlay and gains nothing from being narrower. */
:root[data-nav="mini"] .nav-rail .nav-text { display: none; }

:root[data-nav="mini"] .nav-rail .nav-item,
:root[data-nav="mini"] .nav-rail .nav-branch,
:root[data-nav="mini"] .nav-rail .nav-user,
:root[data-nav="mini"] .nav-rail .nav-sync {
  justify-content: center;
  padding-left: 0; padding-right: 0; gap: 0;
}

:root[data-nav="mini"] .nav-rail .nav-divider { display: block; }

/* The collapse control: a disc straddling the rail's right border.
   It sat in the menu as a labelled row before, where it read as another
   destination and was reported as undiscoverable twice. On the edge it is
   unambiguous — it belongs to the boundary it moves, which is the pattern
   every IDE and admin console has already taught people. */
.nav-edge-toggle {
  position: absolute;
  top: 74px;                       /* level with the branch selector */
  right: -13px;                    /* half outside, centred on the border */
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--ink-800);
  color: var(--warm-500);
  box-shadow: var(--sh-1);
  cursor: pointer;
  z-index: 45;                     /* above the rail's own border */
  transition: color var(--t-base) var(--ease-out),
              border-color var(--t-base) var(--ease-out),
              background var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out);
}
.nav-edge-toggle:hover {
  color: var(--warm-100);
  background: var(--ink-750);
  border-color: var(--line-gold);
  transform: scale(1.08);
}
.nav-edge-toggle:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
/* The chevron points the way the rail is about to move. */
.nav-edge-toggle svg { transition: transform var(--t-base) var(--ease-out); }
:root[data-nav="mini"] .nav-edge-toggle svg { transform: scaleX(-1); }

/* The active marker sits inside the rail once there is no label beside it. */
:root[data-nav="mini"] .nav-rail .nav-item[aria-current="page"]::before { left: -3px; }

/* Tooltip stands in for the hidden label. */
:root[data-nav="mini"] .nav-rail [data-nav-tip] { position: relative; }
:root[data-nav="mini"] .nav-rail [data-nav-tip]:hover::after,
:root[data-nav="mini"] .nav-rail [data-nav-tip]:focus-visible::after {
  content: attr(data-nav-tip);
  position: absolute; left: calc(100% + 14px); top: 50%; transform: translateY(-50%);
  white-space: nowrap; z-index: 60; pointer-events: none;
  padding: .4rem .7rem; border-radius: 8px;
  font-size: .75rem; font-weight: 450; letter-spacing: 0;
  color: var(--warm-100);
  background: rgba(16,16,18,.94);
  border: 1px solid var(--line-strong);
  box-shadow: var(--sh-2);
  backdrop-filter: blur(12px);
}

.nav-chevron { transition: transform var(--t-base) var(--ease-out); }
.nav-rail { transition: width var(--t-base) var(--ease-out); }

/* ==========================================================================
   Floor plan
   ========================================================================== */

.floor-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr));
}
.table-node {
  position: relative; aspect-ratio: 1 / .82; min-height: 96px;
  border-radius: var(--r-md); border: 1px solid var(--tone-br);
  background: linear-gradient(165deg, var(--tone-bg), rgba(11,11,13,.6));
  display: flex; flex-direction: column; justify-content: space-between;
  padding: .65rem .7rem; cursor: pointer; text-align: left;
  transition: all var(--t-base) var(--ease-out);
}
.table-node:hover { transform: translateY(-3px); box-shadow: var(--sh-2); border-color: var(--tone); }
.table-node.is-round { border-radius: 50% / 42%; }
.table-node.is-stool { aspect-ratio: 1 / 1; min-height: 72px; border-radius: 50%; }
.table-node .t-code { font-family: var(--serif); font-size: 1.35rem; line-height: 1; color: var(--warm-100); }
.table-node .t-meta { font-size: .625rem; color: var(--warm-500); letter-spacing: .04em; }
.table-node[data-status="payment_due"] { animation: due 2.6s var(--ease-in-out) infinite; }
@keyframes due {
  0%,100% { box-shadow: 0 0 0 0 rgba(201,127,127,.0); }
  50%     { box-shadow: 0 0 0 4px rgba(201,127,127,.16); }
}
.t-vip { position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; border-radius: 99px;
  background: linear-gradient(180deg, var(--gold-300), var(--gold-500)); color: #17130A;
  font-size: .5rem; font-weight: 800; display: grid; place-items: center; box-shadow: var(--sh-1); }

/* ==========================================================================
   Kitchen / bar tickets
   ========================================================================== */

.ticket {
  border-radius: var(--r-md); border: 1px solid var(--tone-br);
  background: linear-gradient(180deg, var(--ink-800), var(--ink-850));
  overflow: hidden; display: flex; flex-direction: column;
  transition: all var(--t-base) var(--ease-out);
}
.ticket:hover { transform: translateY(-2px); box-shadow: var(--sh-2); }
.ticket-head { padding: .7rem .85rem; background: var(--tone-bg); border-bottom: 1px solid var(--tone-br); }
.ticket-bar { height: 3px; background: var(--tone); opacity: .9; }
.timer-ring { transform: rotate(-90deg); }
.timer-ring circle { fill: none; stroke-linecap: round; }

/* ==========================================================================
   Menu (customer)
   ========================================================================== */

.dish-photo {
  position: relative; overflow: hidden; background: var(--tone-fallback, var(--ink-700));
  background-image: linear-gradient(150deg, color-mix(in srgb, var(--dish, #3A3A42) 85%, #000), color-mix(in srgb, var(--dish, #3A3A42) 30%, #000));
}
.dish-photo img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 900ms var(--ease-out), opacity var(--t-slow) var(--ease-out);
  opacity: 0;
}
.dish-photo img.loaded { opacity: 1; }
.dish-card:hover .dish-photo img { transform: scale(1.055); }
.dish-photo::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 35%, rgba(7,7,8,.82) 100%);
}

.cat-rail { scroll-snap-type: x mandatory; }
.cat-rail > * { scroll-snap-align: start; }

.chip {
  padding: .5rem .95rem; border-radius: 99px; font-size: .75rem; font-weight: 500;
  border: 1px solid var(--line-strong); color: var(--warm-500); white-space: nowrap;
  background: rgba(247,243,234,.02); transition: all var(--t-fast) var(--ease-out);
}
.chip:hover { color: var(--warm-100); border-color: var(--line-gold); }
.chip[aria-selected="true"] {
  background: linear-gradient(180deg, var(--gold-300), var(--gold-500));
  color: #17130A; border-color: transparent; font-weight: 600;
}

/* ==========================================================================
   Motion — entrances only, and only once
   ========================================================================== */

.rise { opacity: 0; transform: translateY(14px); }
.rise.in { opacity: 1; transform: none; transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out); }

.fade { opacity: 0; }
.fade.in { opacity: 1; transition: opacity 700ms var(--ease-out); }

/* Gold shimmer for the hero wordmark. Slow enough to read as light, not animation. */
.shimmer {
  background: linear-gradient(100deg, var(--gold-500) 20%, var(--gold-100) 40%, var(--gold-400) 55%, var(--gold-500) 75%);
  background-size: 200% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: shimmer 7s linear infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }

/* ==========================================================================
   Sheets / drawers
   ========================================================================== */

.sheet-backdrop {
  position: fixed; inset: 0; z-index: 90; background: rgba(4,4,5,.72);
  backdrop-filter: blur(6px); opacity: 0; pointer-events: none;
  transition: opacity var(--t-base) var(--ease-out);
}
.sheet-backdrop.open { opacity: 1; pointer-events: auto; }

.sheet {
  position: fixed; z-index: 91; background: var(--ink-850);
  border: 1px solid var(--line-strong); box-shadow: var(--sh-3);
  transition: transform var(--t-slow) var(--ease-out);
}
.sheet-bottom {
  left: 0; right: 0; bottom: 0; border-radius: var(--r-2xl) var(--r-2xl) 0 0;
  transform: translateY(101%); max-height: 88vh; padding-bottom: env(safe-area-inset-bottom);
}
.sheet-bottom.open { transform: none; }
.sheet-right {
  top: 0; right: 0; bottom: 0; width: min(480px, 100%);
  border-radius: var(--r-xl) 0 0 var(--r-xl); transform: translateX(101%);
}
.sheet-right.open { transform: none; }
.grabber { width: 38px; height: 4px; border-radius: 99px; background: var(--ink-600); margin: .8rem auto .2rem; }

/* ==========================================================================
   Console rhythm
   Density is a function of viewport, not of taste. On a 13" captain tablet the
   console should be efficient; on a 27" manager desk the same screen should
   breathe. Applied here so no view has to think about it.
   ========================================================================== */

@media (min-width: 1280px) {
  .card { border-radius: var(--r-xl); }
  .card.p-5 { padding: 1.5rem; }
  .card.p-6 { padding: 1.75rem; }

  /* Section gaps widen with the screen. */
  main > .grid { gap: 1.25rem; }
  main .space-y-4 > * + * { margin-top: 1.25rem; }
}

@media (min-width: 1680px) {
  .card.p-6 { padding: 2rem; }
  main > .grid { gap: 1.5rem; }
  main .space-y-4 > * + * { margin-top: 1.5rem; }
}

/* Tables: taller rows read faster under pressure than tighter ones. */
@media (min-width: 1280px) {
  main table td { padding-top: 1.05rem; padding-bottom: 1.05rem; }
}

/* A heading and its eyebrow are one unit — never let them separate. */
.eyebrow + h2, .eyebrow + h3 { margin-top: .35rem; }

/* Long-form explanatory copy inside cards. Caps the measure so a paragraph
   never runs the full width of a 27" screen, which is unreadable. */
main p.leading-relaxed { max-width: 68ch; }

/* ==========================================================================
   Utility
   ========================================================================== */

.stack > * + * { margin-top: var(--stack, 1rem); }
.divide-hair > * + * { border-top: 1px solid var(--line); }
.truncate-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tabular { font-variant-numeric: tabular-nums; }
.safe-b { padding-bottom: calc(env(safe-area-inset-bottom) + var(--pb, 0px)); }

/* Print: receipts and invoices only. */
/* A QR, on a card, in a room.
 *
 * Always black on white regardless of skin, because this is a contrast
 * requirement rather than a style one — a phone camera has no opinion about
 * whether the console is in night mode. The white extends past the modules on
 * every side: the quiet zone is part of the symbol, and a code butted against
 * a dark card is a code that reads slowly or not at all. */
.qr-tile {
  background: #fff; border-radius: var(--r-md); padding: 10px;
  display: grid; place-items: center;
}
.qr-tile svg { width: 100%; height: auto; max-width: 220px; display: block; }

@media print {
  /* The console is a fixed rail plus an offset column. Printed as-is, the rail
   * lands on top of the first cards and the offset pushes the rest off the
   * right-hand edge — which is what "the print button does nothing useful"
   * actually looked like. */
  body { background: #fff; color: #000; }
  body::before, body::after { display: none; }
  .no-print, .nav-rail, .sheet, .sheet-backdrop, footer { display: none !important; }
  .print-only { display: block !important; }
  .stage > div { margin-left: 0 !important; }
  main { padding: 0 !important; max-width: none !important; }

  .card {
    border: 1px solid #ddd; box-shadow: none; background: #fff;
    /* A card cut in half across a page break is a card nobody can glue down. */
    break-inside: avoid; page-break-inside: avoid;
  }
  /* Cards are physical objects here — sized so a sheet of A4 yields six that
   * fit a standard table tent without resizing. */
  .qr-sheet { display: grid !important; grid-template-columns: repeat(2, 1fr) !important; gap: 12mm !important; }
  .qr-tile { padding: 0; }
  .qr-tile svg { max-width: 46mm; }

  /* Print in ink, not in theme tokens. */
  .serif, h1, h2, h3, p, span { color: #000 !important; }
  .eyebrow { color: #666 !important; }
  @page { margin: 12mm; }
}
.print-only { display: none; }

/* ==========================================================================
   Light skin — the day service
   ==========================================================================
   Opt-in, and implemented as a token override. Not one rule above is modified:
   every component already reads these custom properties, so redefining the
   ladder *is* the theme. Layout, spacing, hierarchy and interaction are
   identical in both — only the light in the room changes.

   Dark is an exclusive dining room at eleven at night. This is a hotel lobby at
   eleven in the morning: warm ivory, daylight, and gold used the way a good
   printer uses it — foil for ornament, ink for words.

   The one place the brief could not be followed literally: champagne (#C8A56A)
   sits at 2.2:1 on ivory and is unreadable as text, and --accent carries text in
   forty-two places. So the champagne is kept exactly as specified wherever it is
   a *material* — button fills, borders, active indicators, gradients — and text
   uses a deeper bronze from the same family that clears 4.5:1.
   ========================================================================== */

:root[data-skin="light"] {
  /* ---- surfaces: warm, never white, never grey ---- */
  --ink-900:  #FFFFFF00;
  --ink-950:  #FAF7F2;        /* the stage — warm ivory */
  --ink-900s: #F5F1EA;        /* section */
  --ink-850:  #FFFFFF;        /* raised panel */
  --ink-800:  #FFFFFF;        /* card */
  --ink-750:  #F8F5EF;        /* card hover, soft contrast */
  --ink-700:  #F3EFE7;        /* wells, inputs */
  --ink-600:  #E8E1D7;        /* border */
  --ink-500:  #B9AE9C;        /* disabled ink */

  /* ---- ink: rich charcoal and warm grey, never blue-black ---- */
  --warm-100: #1F1B14;        /* 16.0:1 */
  --warm-300: #423B30;        /*  9.6:1 */
  --warm-500: #6E6558;        /*  5.4:1 */
  --warm-700: #857C6B;        /*  3.9:1 — hints and metadata only */

  /* ---- champagne: the material ---- */
  --gold-100: #FBF6EC;
  --gold-300: #DCBE86;
  --gold-400: #C8A56A;        /* THE champagne, exactly as briefed */
  --gold-500: #B79356;        /* hover */
  --gold-700: #8A6D35;
  --gold-900: #F5EEDF;        /* the palest wash, for hover fills */

  /* ---- champagne: the ink. Same family, legible on ivory. ---- */
  --accent:      #8A6D35;     /* 4.6:1 */
  --accent-soft: #A8834A;

  /* ---- semantic accents, reweighted for a light ground ---- */
  --mint-400: #3B7A5F;  --mint-900: #E8F1EB;
  --rose-400: #A64C4C;  --rose-900: #F8E9E9;
  --amber-400:#8E6425;  --amber-900:#F9F0DF;
  --royal-400:#42648F;  --royal-900:#E9EEF6;
  --slate-400:#5C5C68;  --slate-900:#EFEDE8;

  /* ---- lines ---- */
  --line:        #E8E1D7;
  --line-strong: #DAD0C1;
  --line-gold:   rgba(200, 165, 106, .42);

  /* ---- elevation: ambient rather than cast.
         A light room has less depth to trade with, and the long black shadows
         of the night theme read as dirt on ivory. Warm-tinted, low opacity,
         generous blur — the card should sit on the page, not hover above it. */
  --sh-1: 0 1px 2px rgba(94, 78, 47, .05), 0 2px 10px rgba(94, 78, 47, .045);
  --sh-2: 0 2px 6px rgba(94, 78, 47, .06), 0 14px 32px -12px rgba(94, 78, 47, .13);
  --sh-3: 0 6px 14px rgba(94, 78, 47, .07), 0 34px 64px -24px rgba(94, 78, 47, .18);
  --sh-gold: 0 0 0 1px var(--line-gold), 0 10px 30px -14px rgba(200, 165, 106, .5);

  --nav-stuck: rgba(255, 255, 255, .8);

  color-scheme: light;
}

/* The grain film is a dark-room device: it stops large black areas reading as
   dead pixels. On ivory there is no such problem and it only muddies. */
:root[data-skin="light"] body::after,
:root[data-skin="light"] .stage::after { opacity: 0; }

/* ---- glass: invert the tint, or panels sit on the page as smudges ---- */
:root[data-skin="light"] .glass {
  background: rgba(255, 255, 255, .68);
  border-color: var(--line);
}
:root[data-skin="light"] .glass-deep {
  background: rgba(255, 255, 255, .82);
  border-color: var(--line);
}

/* ---- cards: a hairline and ambient depth, lifting a little on hover ---- */
:root[data-skin="light"] .card {
  border-color: var(--line);
  box-shadow: var(--sh-1);
}
:root[data-skin="light"] .card-hover:hover {
  box-shadow: var(--sh-2);
  border-color: var(--line-strong);
}
/* The top-lit edge is a brushed-metal trick and needs almost nothing on ivory. */
:root[data-skin="light"] .lit::before { opacity: .5; }

/* ---- buttons: champagne as a material, with a hairline of depth ---- */
:root[data-skin="light"] .btn-gold {
  background: linear-gradient(180deg, #D4B47C, var(--gold-400));
  color: #241B08;
  border-color: rgba(138, 109, 53, .3);
  box-shadow: 0 1px 2px rgba(94, 78, 47, .12), 0 6px 16px -8px rgba(200, 165, 106, .7);
}
:root[data-skin="light"] .btn-gold:hover {
  background: linear-gradient(180deg, var(--gold-400), var(--gold-500));
  box-shadow: 0 2px 4px rgba(94, 78, 47, .14), 0 10px 22px -8px rgba(200, 165, 106, .8);
}
:root[data-skin="light"] .btn-ghost {
  background: #FFFFFF;
  border-color: var(--line-strong);
  color: var(--warm-300);
}
:root[data-skin="light"] .btn-ghost:hover {
  background: var(--gold-900);
  border-color: var(--line-gold);
  color: var(--accent);
}
:root[data-skin="light"] .btn-quiet:hover { background: var(--ink-750); }

/* ---- inputs: the focus ring is champagne, not the browser's blue ---- */
:root[data-skin="light"] .input {
  background: #FFFFFF;
  border-color: var(--line-strong);
}
:root[data-skin="light"] .input::placeholder { color: #A79C89; }
:root[data-skin="light"] .input:focus {
  border-color: var(--gold-400);
  box-shadow: 0 0 0 3px rgba(200, 165, 106, .18);
}

/* ---- wells sit *into* the page rather than on it ---- */
:root[data-skin="light"] .well {
  background: var(--ink-750);
  border-color: var(--line);
}

/* ---- tables: alternating warmth, and a row that responds ---- */
:root[data-skin="light"] thead tr { background: var(--ink-750); }
:root[data-skin="light"] tbody tr:nth-child(even) { background: rgba(245, 241, 234, .5); }
:root[data-skin="light"] tbody tr:hover { background: var(--gold-900); }

/* ---- navigation: a lobby, not an admin panel ---- */
:root[data-skin="light"] .nav-rail {
  background: rgba(255, 255, 255, .78);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-right-color: var(--line);
}
:root[data-skin="light"] .nav-item { color: var(--warm-500); }
:root[data-skin="light"] .nav-item:hover {
  background: var(--gold-900);
  color: var(--warm-100);
}
:root[data-skin="light"] .nav-item[aria-current="page"] {
  background: var(--gold-900);
  color: var(--warm-100);
  /* Ink rather than a glow: a lit edge on a pale ground reads as a smudge. */
  box-shadow: inset 0 0 0 1px var(--line-gold);
}
:root[data-skin="light"] .nav-item[aria-current="page"]::before {
  box-shadow: none;
}
/* The active marker becomes a champagne rule rather than a glow. */
:root[data-skin="light"] .nav-item[aria-current="page"]::before {
  background: var(--gold-400);
}
:root[data-skin="light"] .nav-edge-toggle {
  background: #FFFFFF;
  border-color: var(--line-strong);
}

/* ---- the collapsed-rail tooltip ----
   Left deliberately dark: an inverted tooltip is the convention and it reads
   crisply against ivory. But its text is --warm-100, which on this skin is
   near-black — so the label has to be pinned to ivory or it disappears into its
   own background. */
:root[data-skin="light"] .nav-rail [data-nav-tip]:hover::after,
:root[data-skin="light"] .nav-rail [data-nav-tip]:focus-visible::after {
  background: rgba(31, 27, 20, .96);
  border-color: rgba(31, 27, 20, .96);
  color: #F7F3EA;
  box-shadow: var(--sh-2);
}

/* ---- sheets and their backdrop ---- */
:root[data-skin="light"] .sheet {
  background: #FFFFFF;
  border-color: var(--line);
  box-shadow: var(--sh-3);
}
:root[data-skin="light"] .sheet-backdrop { background: rgba(56, 48, 30, .28); }

/* ---- the toggle itself ---- */
.skin-toggle {
  display: inline-grid; place-items: center;
  width: 34px; height: 34px; flex: none;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--ink-800);
  color: var(--warm-500);
  cursor: pointer;
  transition: color var(--t-base) var(--ease-out),
              border-color var(--t-base) var(--ease-out),
              background var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out);
}
.skin-toggle:hover {
  color: var(--accent);
  border-color: var(--line-gold);
  transform: translateY(-1px);
}
.skin-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.skin-toggle svg { width: 16px; height: 16px; }

/* Show the icon for the theme you would switch *to* — the convention every
   other toggle has already taught people. */
.skin-toggle [data-skin-sun] { display: none; }
:root[data-skin="light"] .skin-toggle [data-skin-sun]  { display: block; }
:root[data-skin="light"] .skin-toggle [data-skin-moon] { display: none; }

/* Repainting every surface at once looks broken; a short cross-fade reads as
   the lights being brought up. Dropped again straight after, so hovers and
   reveals are not laggy for the rest of the session. */
@media (prefers-reduced-motion: no-preference) {
  .skin-fade, .skin-fade * {
    transition: background-color .32s var(--ease-out),
                border-color .32s var(--ease-out),
                color .32s var(--ease-out) !important;
  }
}

/* A dotted underline marks a control that is a word rather than a button — the
   inline "remove" on a discount, "Discount" on a ticket line. It was already in
   use, but only ever inside an action_button() class argument, where the CSS
   compiler never saw it: the compiler reads markup, and that string is a PHP
   function parameter. The first literal use in an attribute made it visible and
   immediately failed the build, which is the check doing its job. */
.decoration-dotted { text-decoration-style: dotted; }

/* A chip that is switched on. The module grid on the platform console renders
   every module for every venue and marks the enabled ones — without a rule here
   the two states are identical, which makes a switch that reports nothing.

   `.chip[aria-selected]` exists above and is the same idea, but these are
   buttons inside a form rather than a selectable list, and aria-selected on a
   submit button would be a lie about what it is. */
.chip-on {
  color: var(--ink-950);
  background: var(--gold-400);
  border-color: var(--gold-400);
}
.chip-on:hover { color: var(--ink-950); background: var(--gold-300); }

/* What a terminal says when it has taken work the line could not carry.

   Fixed to the bottom rather than inline, because the operator's eyes are on
   the ticket and not on the form they just submitted — and because it has to
   be readable from arm's length on a tablet propped against a till. It leaves
   on its own after four seconds; a dismissable banner is one more thing to
   press during service. */
.offline-notice {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  transform: translate(-50%, 1rem);
  z-index: 90;
  max-width: min(30rem, calc(100vw - 2rem));
  padding: .8rem 1.1rem;
  border-radius: var(--r-md);
  border: 1px solid var(--tone-line, var(--line));
  background: var(--panel);
  color: var(--warm-200);
  font-size: 12.5px;
  line-height: 1.5;
  box-shadow: var(--sh-2);
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
.offline-notice.is-on { opacity: 1; transform: translate(-50%, 0); }

/* A dish 86'd since this screen was cached.
   The service worker can serve a POS page from an hour ago; the pull knows what
   has come off since. Marked rather than removed — a tile that vanishes leaves
   an operator hunting for a dish that is simply gone, and one struck through
   answers the question they were about to ask. */
[data-unavailable] { opacity: .4; }
[data-unavailable] [data-menu-price] { text-decoration: line-through; }

/* ── the availability calendar ────────────────────────────────────────────────
   Four states, and they are not shades of one thing.

   A closed day and a sold-out day look identical on a naive heat map and mean
   opposite things: one has rooms standing empty because somebody decided so,
   the other has none left because they sold. An oversold day is a third fact
   again — it is not "very full", it is a promise the property may not be able
   to keep, and it wants a colour that says so.

   Written by hand rather than as utilities because the compiler has no opacity
   modifier, and `bg-[var(--rose)]/15` compiled to nothing at all — a cell that
   silently lost its colour on a screen whose entire job is colour. */
.cal-tight { background: rgba(216,190,134,.14); }                 /* one left      */
.cal-full  { background: rgba(201,127,127,.14); }                 /* none left     */
.cal-over  { background: rgba(201,127,127,.30); color: var(--rose-400); font-weight: 600; }
.cal-shut  { background: rgba(138,138,150,.16); color: var(--warm-700); }
