/* =========================================================
   lux.css — the luxury layer for the Echelon Brew ERP

   Loaded AFTER style.css, so it only re-dresses what is already there.
   It changes no layout, no spacing that content depends on, and no
   behaviour: every rule here is colour, depth, light or motion.

   The staff app keeps its themes — this layer reads the theme's own
   --gold / --surface variables, so Espresso, Midnight, Forest, Ivory and
   Mocha each get the same treatment in their own palette.

   Everything heavy is disabled for touch devices and for anyone who has
   asked their system for reduced motion; a busy till should never drop a
   frame because of decoration.
   ========================================================= */

/* ---------- ambient depth behind the whole app ----------
   Painted onto the body's own background rather than a positioned pseudo
   element. An earlier version used ::before/::after overlays and had to push
   the app above them with `position:relative`, which silently overrode the
   `position:fixed` on .sidebar, .topbar and .modal-overlay — collapsing the
   mobile drawer and rendering modals inline instead of over the page. Layering
   the gradients into `background-image` needs no stacking context at all. */
body{
  background-image:
    radial-gradient(900px 480px at 88% -8%, rgba(216,185,121,.07), transparent 62%),
    radial-gradient(720px 420px at -6% 108%, rgba(169,120,74,.06), transparent 62%);
  background-attachment:fixed, fixed;
  background-repeat:no-repeat, no-repeat;
}
/* the faintest grain, so large dark panels do not band on cheap screens.
   pointer-events:none, so it can sit on top without eating a single tap. */
body::after{
  content:"";position:fixed;inset:0;pointer-events:none;z-index:9999;opacity:.03;
  mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 .85 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

/* ---------- sidebar: a lit edge instead of a flat border ---------- */
.sidebar{
  background:linear-gradient(180deg, var(--sidebar) 0%, color-mix(in srgb, var(--sidebar) 88%, #000) 100%);
  box-shadow:inset -1px 0 0 rgba(216,185,121,.10), 4px 0 34px rgba(0,0,0,.28);
}
.nav-item{position:relative;border-radius:10px;transition:background .35s cubic-bezier(.2,.7,.2,1),color .35s,transform .35s;}
.nav-item::before{
  content:"";position:absolute;left:0;top:50%;transform:translateY(-50%) scaleY(0);
  width:2px;height:64%;border-radius:2px;
  background:linear-gradient(180deg,var(--gold),transparent);
  transition:transform .4s cubic-bezier(.16,1,.3,1);
}
.nav-item:hover{transform:translateX(2px);}
.nav-item.active::before{transform:translateY(-50%) scaleY(1);}
.nav-item.active{
  background:linear-gradient(90deg, color-mix(in srgb, var(--gold) 14%, transparent), transparent 78%);
}
.nav-group-label{letter-spacing:.34em;opacity:.55;}

/* ---------- top bar: frosted, with a hairline of gold ---------- */
.topbar{
  backdrop-filter:blur(16px) saturate(1.08);-webkit-backdrop-filter:blur(16px) saturate(1.08);
  box-shadow:0 1px 0 rgba(216,185,121,.12), 0 12px 28px -22px rgba(0,0,0,.7);
}

/* ---------- cards: gentle lift, lit top edge ---------- */
.card{
  position:relative;
  border:1px solid color-mix(in srgb, var(--border) 82%, var(--gold) 18%);
  box-shadow:0 1px 0 rgba(255,255,255,.03) inset, var(--shadow-sm);
  transition:transform .45s cubic-bezier(.16,1,.3,1), box-shadow .45s, border-color .45s;
}
.card::after{
  content:"";position:absolute;left:14px;right:14px;top:0;height:1px;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgba(216,185,121,.34),transparent);
  opacity:.7;
}
.card:hover{
  transform:translateY(-2px);
  box-shadow:0 18px 44px -26px rgba(0,0,0,.75), 0 1px 0 rgba(255,255,255,.04) inset;
  border-color:color-mix(in srgb, var(--border) 55%, var(--gold) 45%);
}

/* ---------- stat tiles: the hero numbers ---------- */
.stat .val{
  font-variant-numeric:lining-nums tabular-nums;
  letter-spacing:.005em;
  background:linear-gradient(175deg, var(--text) 12%, color-mix(in srgb, var(--gold) 78%, var(--text)) 96%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.stat .ico{
  position:relative;overflow:hidden;
  box-shadow:0 8px 20px -12px rgba(0,0,0,.7), 0 0 0 1px rgba(216,185,121,.14) inset;
}
/* a slow sweep of light across the icon chip */
.stat .ico::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(120deg,transparent 34%,rgba(255,255,255,.30) 50%,transparent 66%);
  transform:translateX(-140%);
}
.card:hover .stat .ico::after{transition:transform 1.1s cubic-bezier(.16,1,.3,1);transform:translateX(140%);}
.stat .lbl{letter-spacing:.16em;text-transform:uppercase;font-size:10px;opacity:.75;}

/* ---------- buttons ---------- */
.btn{position:relative;overflow:hidden;transition:transform .3s cubic-bezier(.16,1,.3,1),box-shadow .3s,filter .3s;}
.btn:active{transform:translateY(1px) scale(.995);}
.btn-primary{
  background:linear-gradient(120deg, color-mix(in srgb,var(--gold) 92%, #fff 8%), var(--gold) 52%, color-mix(in srgb,var(--gold) 78%, #000 22%));
  box-shadow:0 12px 26px -14px color-mix(in srgb,var(--gold) 70%, transparent), inset 0 1px 0 rgba(255,255,255,.42);
}
.btn-primary:hover{box-shadow:0 18px 36px -14px color-mix(in srgb,var(--gold) 78%, transparent), inset 0 1px 0 rgba(255,255,255,.5);}
/* light sweeps across a primary button on hover */
.btn-primary::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(120deg,transparent 36%,rgba(255,255,255,.42) 50%,transparent 64%);
  transform:translateX(-150%);
}
.btn-primary:hover::after{transition:transform .9s cubic-bezier(.16,1,.3,1);transform:translateX(150%);}
.btn-ghost{transition:border-color .35s,color .35s,background .35s,transform .3s;}
.btn-ghost:hover{border-color:var(--gold);color:var(--gold);background:color-mix(in srgb,var(--gold) 8%, transparent);}

/* ---------- tables ---------- */
.tbl thead th{
  letter-spacing:.2em;text-transform:uppercase;font-size:10px;
  background:linear-gradient(180deg, color-mix(in srgb,var(--gold) 8%, transparent), transparent);
  border-bottom:1px solid color-mix(in srgb,var(--border) 60%, var(--gold) 40%);
}
.tbl tbody tr{transition:background .3s;}
.tbl tbody tr:hover{background:color-mix(in srgb,var(--gold) 6%, transparent);}

/* ---------- badges & chips ---------- */
.badge,.chip{
  letter-spacing:.1em;text-transform:uppercase;font-size:10px;
  box-shadow:0 0 0 1px rgba(216,185,121,.12) inset;
}

/* ---------- inputs ---------- */
.input,.select,textarea.input{transition:border-color .3s,box-shadow .3s,background .3s;}
.input:focus,.select:focus,textarea.input:focus{
  border-color:var(--gold);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--gold) 18%, transparent);
}

/* ---------- modals ---------- */
.modal-overlay{backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px);background:rgba(6,5,3,.62);}
.modal{
  border:1px solid color-mix(in srgb,var(--border) 55%, var(--gold) 45%);
  box-shadow:0 44px 100px -40px rgba(0,0,0,.9), 0 0 0 1px rgba(255,255,255,.03) inset;
  animation:luxRise .5s cubic-bezier(.16,1,.3,1);
}
@keyframes luxRise{from{opacity:0;transform:translateY(16px) scale(.985)}to{opacity:1;transform:none}}
.modal-head{border-bottom:1px solid color-mix(in srgb,var(--border) 60%, var(--gold) 40%);}
.modal-head h3{letter-spacing:.01em;}

/* ---------- toasts ---------- */
.toast{
  border:1px solid color-mix(in srgb,var(--border) 50%, var(--gold) 50%);
  box-shadow:0 22px 48px -22px rgba(0,0,0,.8);
  animation:luxSlide .45s cubic-bezier(.16,1,.3,1);
}
@keyframes luxSlide{from{opacity:0;transform:translateX(28px)}to{opacity:1;transform:none}}

/* ---------- card headers: an icon is a mark, not an illustration ----------
   UI.icon() emits an SVG with no intrinsic size, so an icon dropped into a
   card header (Celebrations Today) stretched to fill the whole card and left
   a huge void beside it. Constrain them wherever they appear as decoration. */
.card-head svg{width:18px;height:18px;flex:0 0 auto;}
.card-head h3 svg{width:16px;height:16px;vertical-align:-2px;}
.empty svg{width:38px;height:38px;opacity:.5;margin-bottom:6px;}

/* Cards sit at their natural height instead of stretching to match the tallest
   in the row — that stretching is what left big empty panels on the dashboard. */
.content .grid{align-items:start;}

/* ---------- page headings ---------- */
.page-head h1,.ph h1{letter-spacing:-.01em;}
.page-head h1::after,.ph h1::after{
  content:"";display:block;width:46px;height:2px;margin-top:10px;border-radius:2px;
  background:linear-gradient(90deg,var(--gold),transparent);
}

/* ---------- content entrance: one quiet fade, never a parade ---------- */
#page-content{animation:luxIn .5s cubic-bezier(.16,1,.3,1);}
@keyframes luxIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

/* ---------- kanban (orders board) ---------- */
.kanban .col h4{letter-spacing:.2em;text-transform:uppercase;font-size:11px;}
.kc{transition:transform .35s cubic-bezier(.16,1,.3,1),box-shadow .35s,border-color .35s;}
.kc:hover{transform:translateY(-2px);box-shadow:0 16px 34px -22px rgba(0,0,0,.8);border-color:color-mix(in srgb,var(--border) 50%, var(--gold) 50%);}

/* ---------- avatar / user chip ---------- */
.avatar,.user-avatar,.sidebar .who .av{
  box-shadow:0 0 0 1px rgba(216,185,121,.35), 0 6px 18px -8px rgba(0,0,0,.7);
}

/* ---------- scrollbars ---------- */
*::-webkit-scrollbar{width:10px;height:10px;}
*::-webkit-scrollbar-track{background:transparent;}
*::-webkit-scrollbar-thumb{
  background:linear-gradient(180deg, color-mix(in srgb,var(--gold) 42%, transparent), color-mix(in srgb,var(--gold) 16%, transparent));
  border-radius:10px;border:2px solid transparent;background-clip:padding-box;
}
*::-webkit-scrollbar-thumb:hover{background:linear-gradient(180deg,var(--gold),color-mix(in srgb,var(--gold) 45%, transparent));background-clip:padding-box;}

/* =========================================================
   QUIET REFRESH — the cure for the boot "flicker"
   ---------------------------------------------------------
   On open, sync attaches ~35 Firestore listeners and each first
   snapshot re-renders the page. style.css plays rise / riseSm /
   glowin on .content, .page-head, every .grid child and every
   top-level card, and lux.css plays luxIn on #page-content. Six
   overlapping entrance animations, replayed dozens of times over
   four seconds, is precisely what the eye reads as flickering.

   core.js sets App._quiet during a data-driven reload and stamps
   .quiet on #page-content. Navigation still animates in full; a
   background refresh repaints silently, in place.
   ========================================================= */
.content.quiet,
.content.quiet .page-head,
.content.quiet .grid > *,
.content.quiet > .card,
.content.quiet > .table-wrap,
.content.quiet > .tabs,
.content.quiet [id$="-table"],
.content.quiet [id$="-body"],
.content.quiet [id$="-grid"]{
  animation:none !important;
  animation-delay:0s !important;
  opacity:1 !important;
  transform:none !important;
}
/* the luxIn lift on the page shell itself — same story */
#page-content.quiet{animation:none !important;}
/* and no hover-lift / shadow transitions mid-repaint either: a card that
   settles into place while its transition is still running looks like a
   second flicker on slower phones */
.content.quiet .card,
.content.quiet .stat,
.content.quiet .kc{transition:none !important;}

/* =========================================================
   SYNC BAR — an animation instead of a flicker
   ---------------------------------------------------------
   The old "Syncing…" pill was removed because it covered a button.
   This replaces it with something that cannot: a 2px indeterminate
   gold thread across the very top of the viewport, above everything,
   click-through, and invisible unless work is actually in flight.
   ========================================================= */
#ecbSyncBar{
  position:fixed;top:0;left:0;right:0;height:2px;
  z-index:10001;pointer-events:none;
  opacity:0;transition:opacity .28s ease;
  background:color-mix(in srgb, var(--gold, #c9a24b) 12%, transparent);
  overflow:hidden;
}
#ecbSyncBar.on{opacity:1;}
#ecbSyncBar::before{
  content:"";position:absolute;top:0;bottom:0;left:0;width:40%;
  border-radius:2px;
  background:linear-gradient(90deg,
    transparent,
    color-mix(in srgb, var(--gold, #c9a24b) 55%, transparent) 28%,
    #f0d99a 50%,
    color-mix(in srgb, var(--gold, #c9a24b) 55%, transparent) 72%,
    transparent);
  box-shadow:0 0 10px color-mix(in srgb, var(--gold, #c9a24b) 45%, transparent);
  transform:translateX(-100%);
  animation:ecbSweep 1.15s cubic-bezier(.45,0,.25,1) infinite;
}
@keyframes ecbSweep{
  0%  {transform:translateX(-100%);}
  100%{transform:translateX(350%);}
}
/* installed app: sit under the notch, not behind it */
@media (display-mode:standalone),(display-mode:fullscreen){
  #ecbSyncBar{top:env(safe-area-inset-top, 0px);}
}
/* browsers without color-mix still get a visible gold thread */
@supports not (color: color-mix(in srgb, red 50%, blue)){
  #ecbSyncBar{background:rgba(201,162,75,.14);}
  #ecbSyncBar::before{background:linear-gradient(90deg,transparent,#c9a24b 35%,#f0d99a 50%,#c9a24b 65%,transparent);}
}
/* a whisper of a tint on the workspace while the first wave lands, so the
   bar reads as "the app is filling in" rather than as a stray line */
body.is-syncing .topbar{
  box-shadow:0 1px 0 color-mix(in srgb, var(--gold, #c9a24b) 18%, transparent);
}

/* =========================================================
   RESTRAINT — a till must stay fast
   ========================================================= */
/* =========================================================
   PHONE / INSTALLED APP
   Fixes for the installed PWA: no horizontal drift, charts that fit,
   legends that wrap instead of stretching the page, and no dead scroll.
   ========================================================= */
@media (max-width:680px){
  html,body{max-width:100%;overflow-x:hidden;}
  #app,.content,.card,.table-wrap{max-width:100%;}
  /* charts: never wider than the card, legend under the ring */
  .donut-wrap{flex-direction:column;align-items:stretch;gap:12px;}
  .donut-wrap>svg{align-self:center;}
  .donut-wrap>div{min-width:0 !important;width:100%;}
  .card svg{max-width:100%;height:auto;}
  /* a card must never force the page wider than the screen */
  .card{overflow:hidden;}
  .table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;}
  /* the grain overlay is pure decoration — skip the repaint on phones */
  body::after{display:none;}
  /* stat tiles read better stacked two-up than squeezed four-up */
  .grid.cols-4{grid-template-columns:repeat(2,1fr);gap:10px;}
  .stat .val{font-size:20px;}
  .stat .lbl{font-size:9px;letter-spacing:.12em;}
  /* page actions wrap instead of overflowing the header */
  .page-head{align-items:flex-start;}
  .page-actions .btn{flex:1 1 auto;justify-content:center;}
}
/* installed app: keep content clear of the notch and the home indicator, and
   stop the body from scrolling past the end of the content */
@media (display-mode:standalone),(display-mode:fullscreen){
  html,body{overscroll-behavior-y:none;}
  .content{padding-bottom:calc(28px + env(safe-area-inset-bottom));}
}

@media (hover:none){
  .card:hover,.kc:hover{transform:none;}
  .btn-primary::after,.stat .ico::after{display:none;}
  body::after{display:none;}                 /* skip the grain on phones */
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001s !important;transition-duration:.001s !important;}
  #page-content,.modal,.toast{animation:none !important;}
  /* the sweep would strobe at .001s — show a steady gold thread instead */
  #ecbSyncBar::before{animation:none !important;transform:none !important;width:100% !important;opacity:.55;}
}
/* older browsers without color-mix keep the theme's own colours — every rule
   above degrades to "no change" rather than to an unreadable one */
@supports not (color: color-mix(in srgb, red 50%, blue)){
  .card{border-color:var(--border);}
  .nav-item.active{background:var(--sidebar-active);}
  .tbl tbody tr:hover{background:var(--surface-2);}
}
