/* Brand typeface (Trueno), served from FONTS_DIR (see .env — currently the
   real font pack, filenames like "truenorg.otf"). Every reasonable filename
   variant is listed so this keeps working regardless of which font pack
   naming convention is in FONTS_DIR; the browser just skips any URL that
   404s and falls back to the system font stack below, so this is safe
   either way. */
@font-face {
  font-family: "Trueno";
  src: url("/fonts/truenorg.otf") format("opentype"),
       url("/fonts/Trueno-Regular.otf") format("opentype"),
       url("/fonts/Trueno-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Trueno";
  src: url("/fonts/truenolt.otf") format("opentype"),
       url("/fonts/Trueno-Light.otf") format("opentype"),
       url("/fonts/Trueno-Light.ttf") format("truetype");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Trueno";
  src: url("/fonts/truenosbd.otf") format("opentype"),
       url("/fonts/Trueno-SemiBold.otf") format("opentype"),
       url("/fonts/Trueno-SemiBold.ttf") format("truetype");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  --gold: #B08D57;
  --bg: #FAF6EC;
  --surface: #FFFFFF;
  --line: #E7E5DF;
  --ink: #1C1B18;
  --ink-soft: #6B6862;
  --ink-faint: #9C988F;
  --accent: #B08D57;
  --accent-soft: #F3E9DA;
}

* { box-sizing: border-box; }
body {
  font-family: "Trueno", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  font-weight: 300;
  /* Soft radial page canvas — reverted to black top-left / gold-white
     bottom-right (the original approved orientation), with the black
     region pulled back ~40%: its stops now dissolve into gold by ~34%
     of the frame and are fully gone by ~48%, instead of sweeping out to
     76% as in the first build. It now reads as a contained corner accent
     rather than dominating the page. Approved mockup:
     We_Curate_Radial_Gradient_Mockup_v2.html. Text sitting directly over
     the black corner (.dash-greeting, .dash-hint) is set in white with a
     soft shadow — see those rules below — since dark ink is unreadable
     there. Cards use the glass treatment further down. */
  background:
    radial-gradient(circle at 8% 4%, #000000 0%, #1c1b18 12%, #4a3a22 22%, #B08D57 34%, transparent 48%),
    radial-gradient(circle at 90% 94%, #B08D57 0%, #d9c79e 38%, #f7f2e8 62%, #FFFFFF 82%, #FFFFFF 100%),
    #f4efe4;
  background-attachment: fixed;
  color: var(--ink);
  margin: 0;
  /* Sticky footer: body is a full-height flex column so .app-footer sits
     pinned to the bottom of the viewport on short pages (e.g. login)
     instead of floating right under the content with dead space below
     it, while still flowing naturally after the content on taller pages
     (it just gets pushed further down, no special-casing needed). */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.topbar {
  background: #111111;
  color: #fff;
  padding: 17px 32px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: relative;
}
/* Thin brass rule under the header — a small signature touch echoing gilt
   trim on porcelain, in place of the flat 2px solid border this used to
   have. */
.topbar-rule {
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent) 20%, var(--accent) 80%, transparent);
}
/* RAK Porcelain mark sits in normal flex flow (left-aligned, first child).
   Served as SVG/high-res PNG by /branding/logo-white so it stays crisp at
   this height on any screen density — see main.py. */
.topbar-logo-rak {
  height: 48px;
  width: auto;
  display: block;
}
/* We Curate wordmark is absolutely centered in the bar, independent of
   the RAK logo's width on the left and the user-email block on the
   right. Served by /branding/wecurate-logo-white, a transparent-ink SVG
   (no background box) so it sits directly on the topbar's own dark
   background rather than carrying its own. */
.topbar-logo-wecurate {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  height: 41px;
  width: auto;
  display: block;
}
.topbar a { color: #cfd8e3; text-decoration: none; font-size: 14px; }
.topbar-admin-link { color: var(--accent) !important; font-weight: 600; }
.wrap { max-width: 640px; margin: 48px auto; padding: 0 20px; flex: 1 0 auto; width: 100%; }
.wrap.wrap-wide { max-width: 1180px; }

.app-footer {
  flex-shrink: 0;
  text-align: center;
  padding: 24px 20px 32px;
  font-size: 12px;
  color: #9a9490;
  letter-spacing: 0.01em;
}
.app-footer-credit {
  display: inline-block;
  margin-left: 10px;
  padding-left: 10px;
  border-left: 1px solid #d8d2cb;
}
.card {
  /* Glass treatment: translucent white over the radial page gradient
     rather than a flat opaque surface, so the gradient stays faintly
     visible through the card instead of being fully blocked. Falls back
     to a near-opaque white in browsers without backdrop-filter support. */
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 14px;
  padding: 32px;
  margin-bottom: 24px;
  box-shadow: 0 2px 8px rgba(28,27,24,0.06), 0 18px 46px rgba(28,27,24,0.16);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card { background: #FDFCF9; }
}
/* Horizontal 3-up layout for the dashboard's mode cards — stacks back to a
   single column on narrow screens rather than squeezing three columns down
   to nothing. */
.cards-row {
  display: flex;
  gap: 20px;
  align-items: stretch;
}
.cards-row .card { flex: 1 1 0; margin-bottom: 0; min-width: 0; }
@media (max-width: 900px) {
  .cards-row { flex-direction: column; }
}
h1 { font-size: 22px; margin-top: 0; font-weight: 600; }
h2 { font-size: 17px; margin-top: 0; font-weight: 600; }
label { display: block; font-size: 13px; color: #555; margin: 14px 0 6px; }
input[type=text], input[type=email], input[type=password], input[type=file] {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  font-size: 14px;
  box-shadow: inset 0 1px 2px rgba(28,27,24,0.05);
}
input[type=text]:focus, input[type=email]:focus, input[type=password]:focus {
  outline: none;
  border-color: var(--accent);
}
button {
  margin-top: 18px;
  background: #111111;
  color: #fff;
  border: none;
  padding: 11px 20px;
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
  box-shadow: 0 4px 10px rgba(17,17,17,0.18);
}
button:hover { background: #2b2b2b; }
.error { background: #FCEBEB; color: #B23B3B; padding: 10px 14px; border-radius: 8px; font-size: 13px; margin-bottom: 10px; }
.success { background: #E9F7EE; color: #226B3A; padding: 10px 14px; border-radius: 8px; font-size: 13px; margin-bottom: 10px; }
.hint { color: #777; font-size: 12.5px; margin-top: 10px; }

/* Show/hide-password eye toggle — admin-only convenience, see the inline
   script in login.html/register.html. Hidden by default (JS reveals it
   only when the typed email matches an admin address); overrides the
   global `button` rule's dark-filled look since this needs to sit as a
   quiet icon inside the password field, not a full call-to-action button. */
.pwd-field-wrap { position: relative; }
.pwd-field-wrap input[type=password], .pwd-field-wrap input[type=text] { padding-right: 42px; }
.pwd-toggle-btn {
  display: none;
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  align-items: center; justify-content: center;
  width: 30px; height: 30px;
  margin: 0; padding: 0;
  background: none; border: none; box-shadow: none;
  color: #9C988F; cursor: pointer;
}
.pwd-toggle-btn:hover { background: none; color: #555; }
.pwd-toggle-btn svg { width: 18px; height: 18px; }
.pwd-toggle-btn .icon-eye-off { display: none; }
.pwd-toggle-btn.pwd-visible .icon-eye { display: none; }
.pwd-toggle-btn.pwd-visible .icon-eye-off { display: block; }
.badge { display: inline-block; background: #EFEFEF; border-radius: 12px; padding: 2px 10px; font-size: 11px; color: #555; margin-left: 8px; }
.badge-auto { background: var(--accent-soft); color: var(--accent); }
.badge-manual, .badge-tool { background: #EFEDE7; color: var(--ink-soft); }

/* ------------------------------------------------------------ login (split) --
   Two-column layout: form on the left, an illustrative "porcelain rim"
   panel on the right (swap the SVG rings for real ambience photography
   whenever that's wired up — see AMBIENCE_IMAGES_DIR / CATALOGUE_COVERS_DIR
   in .env for where that photo library already lives). Falls back to a
   single column on narrow screens so it never gets cramped. */
.wrap.wrap-login { max-width: 1040px; margin: 48px auto; padding: 0 20px; }
.login-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 520px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(28,27,24,0.04), 0 8px 20px rgba(28,27,24,0.06);
}
@media (max-width: 820px) {
  .login-split { grid-template-columns: 1fr; min-height: 0; }
  .login-hero { display: none; }
}
.login-form-side {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px 24px;
}
.login-card-inner { width: 340px; }
.login-wordmark {
  font-family: "Trueno";
  font-weight: 300;
  font-size: 13px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0.3;
  margin: 0 0 26px;
}
.login-card-inner h1 { font-size: 28px; margin: 0 0 6px; letter-spacing: -0.01em; }
.login-card-inner p.sub { font-size: 13.5px; color: var(--ink-soft); margin: 0 0 26px; font-weight: 400; }
.login-hero {
  position: relative; overflow: hidden;
  background: radial-gradient(circle at 30% 25%, #2C2820, #141310 70%);
}
.login-hero svg { position: absolute; inset: 0; width: 100%; height: 100%; }
/* We Curate's wordmark, centred inside the innermost ring. Width is a %
   of the panel so it scales with the circles; height:auto keeps the
   logo's own aspect ratio (no stretching/cropping). Wider percentage than
   the RAK mark this replaced, since the wordmark is a wide/short shape
   (~2.1:1) rather than the RAK crown+text lockup's tall/narrow one — this
   keeps it reading at a comparable visual size inside the circle. */
.login-hero-logo {
  position: absolute; left: 50%; top: 42.6%; transform: translate(-50%, -50%);
  width: 27%; max-width: 153px; height: auto;
}
.login-hero-copy { position: absolute; left: 36px; bottom: 36px; right: 36px; color: #F1EEE6; }
.login-hero-copy .kicker {
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 8px; font-weight: 600;
}
.login-hero-copy p { font-family: "Trueno"; font-weight: 600; font-size: 19px; line-height: 1.4; margin: 0; max-width: 300px; }

/* ------------------------------------------------------------ dashboard --*/
/* The greeting sits directly over the page gradient's black corner, so —
   unlike the rest of the (dark-ink-on-light) UI — it's set in white with
   a soft shadow to stay readable there, same treatment as the approved
   gradient mockup's header. */
.dash-greeting { font-size: 24px; font-weight: 600; margin: 0 0 4px; color: #fff; text-shadow: 0 1px 12px rgba(0,0,0,0.35); }
.dash-greeting-sub { font-size: 13px; color: rgba(255,255,255,0.82); margin: 0 0 22px; font-weight: 400; text-shadow: 0 1px 10px rgba(0,0,0,0.3); }
/* Demo-mode banner on the dashboard — same reasoning as the greeting
   above; .hint elsewhere (e.g. password hints on solid white cards) is
   untouched. */
.dash-hint { color: rgba(255,255,255,0.85); text-shadow: 0 1px 10px rgba(0,0,0,0.3); }

.recent-strip { margin-bottom: 26px; }
.recent-title {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-faint); font-weight: 600; margin-bottom: 10px;
}
.recent-list { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 2px; }
.recent-item {
  flex: 0 0 200px; border: 1px solid var(--line); border-radius: 8px; padding: 12px 14px;
  box-shadow: 0 1px 2px rgba(28,27,24,0.03); background: var(--surface);
}
.recent-item .fname {
  font-size: 12.5px; font-weight: 600; margin-bottom: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.recent-item .fmeta { font-size: 11px; color: var(--ink-faint); }
.recent-empty { font-size: 12.5px; color: var(--ink-faint); }

.section-rule { height: 1px; background: linear-gradient(90deg, var(--accent) 0, var(--line) 40px); margin: 0 0 22px; }

.card-top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.card-icon {
  width: 32px; height: 32px; border-radius: 8px; background: var(--accent-soft);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.card-icon svg { width: 16px; height: 16px; stroke: var(--accent); }

.dropzone {
  border: 1.5px dashed var(--line); border-radius: 8px; padding: 14px 10px; margin-top: 6px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  text-align: center; background: var(--bg); cursor: pointer;
}
.dropzone.dz-active { border-color: var(--accent); background: var(--accent-soft); }
.dropzone.dz-filled { border-style: solid; border-color: var(--accent); }
.dropzone svg { width: 18px; height: 18px; stroke: var(--ink-faint); }
.dropzone .dz-text { font-size: 11.5px; color: var(--ink-soft); }
.dropzone .dz-text b { color: var(--ink); font-weight: 600; }
.dropzone input[type=file] { display: none; }

.actions-row { display: flex; gap: 10px; margin-top: 4px; }
.actions-row button { flex: 1 1 0; margin-top: 0; }
button.btn-outline {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--ink);
  box-shadow: none;
}
button.btn-outline:hover { background: var(--bg); }
.upload-step-hint { font-size: 12.5px; color: var(--ink-faint); margin-top: 10px; }

/* "Generate a catalogue" unit — Salesforce (automated) and Upload (manual)
   are two sources feeding the same outcome, so they live in one card behind
   a small source toggle instead of two separate cards. Product Finder is a
   different job (search, not generate) and stays its own unit. */
/* Rounded "pill track" toggle (Salesforce / Upload a file) — a single
   light track holding both options, active one filled dark, matching the
   approved gradient mockup rather than two separately-bordered buttons. */
.source-tabs {
  display: flex; justify-content: center; align-items: center;
  width: fit-content; gap: 4px; margin: 0 auto 16px;
  background: var(--bg); border-radius: 10px; padding: 4px;
}
.tab-btn {
  padding: 8px 20px; font-size: 12px; font-weight: 600;
  border-radius: 8px; border: none;
  background: transparent; color: var(--ink-soft); cursor: pointer;
}
.tab-btn.active { background: var(--ink); color: #fff; }
.tab-pane.hidden { display: none; }
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
th, td { text-align: left; padding: 6px 4px; border-bottom: 1px solid #eee; font-size: 13px; }

button:disabled { opacity: 0.6; cursor: not-allowed; }

/* Product Finder review screen */
.pf-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  align-items: flex-end;
  margin: 16px 0;
  padding: 14px 16px;
  background: #F7F7F8;
  border-radius: 8px;
}
.pf-toolbar-group { display: flex; flex-direction: column; gap: 6px; }
.pf-toolbar-group select, .pf-toolbar-group input[type=text] {
  padding: 8px 10px;
  border: 1px solid #D0D3D8;
  border-radius: 6px;
  font-size: 13px;
}
.pf-toolbar-buttons { flex-direction: row; align-items: flex-end; gap: 8px; }
.pf-btn-ghost {
  background: #fff;
  color: #111;
  border: 1px solid #D0D3D8;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 12.5px;
  cursor: pointer;
  margin-top: 0;
}
.pf-btn-ghost:hover { background: #F0F0F0; }

.pf-table-wrap {
  max-height: 560px;
  overflow-y: auto;
  border: 1px solid #E3E5E8;
  border-radius: 8px;
}
.pf-table { width: 100%; border-collapse: collapse; margin-top: 0; }
.pf-table thead th {
  position: sticky;
  top: 0;
  background: #1A1A1A;
  color: #fff;
  font-size: 12px;
  padding: 8px 10px;
  z-index: 1;
}
.pf-table td { padding: 7px 10px; border-bottom: 1px solid #F0F0F0; font-size: 13px; vertical-align: top; }
.pf-table tbody tr:hover { background: #FAFAFA; }
.pf-muted { color: #777; font-size: 12.5px; }

.pf-submit-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 16px;
}
.pf-submit-bar .hint { margin-top: 0; }

.loading-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(17, 17, 17, 0.55);
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.loading-overlay.visible { display: flex; }
.loading-card {
  background: #fff;
  border-radius: 10px;
  padding: 36px 40px;
  text-align: center;
  max-width: 340px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.25);
  perspective: 600px;
}

/* A small collection of pure-CSS 3D outline loaders — no spinner GIF, no
   animation library. One of three variants is picked at random per
   generation (see dashboard.html's pickLoaderVariant) so returning users
   see a bit of variety instead of the same flat circle every time. */
.loader-3d {
  width: 52px; height: 52px;
  margin: 0 auto 18px;
  position: relative;
  transform-style: preserve-3d;
}
.loader-3d .ring { position: absolute; inset: 0; border: 3px solid transparent; border-radius: 50%; }
.loader-3d .ring-2 { display: none; }

/* Variant: spinning plate — a single ring tilted like a plate rim, turning
   on its own axis. The most "porcelain" of the three. */
.loader-3d.variant-plate .ring-1 {
  border-top-color: var(--accent);
  border-bottom-color: var(--accent);
  animation: loader-plate-spin 1.4s linear infinite;
}

/* Variant: orbit rings — a gold ring and a dark ring tumbling on
   different axes at different speeds, like a small gyroscope. */
.loader-3d.variant-orbit .ring-1 {
  border-top-color: var(--accent);
  border-bottom-color: var(--accent);
  animation: loader-orbit-1 1.6s linear infinite;
}
.loader-3d.variant-orbit .ring-2 {
  display: block;
  inset: 9px;
  border-left-color: var(--ink);
  border-right-color: var(--ink);
  animation: loader-orbit-2 1.15s linear infinite reverse;
}

/* Variant: tumbling diamond — two rotated squares turning through all
   three axes at once, for a faceted, gem-like feel. */
.loader-3d.variant-diamond .ring-1 {
  border-radius: 5px;
  border-color: var(--ink);
  animation: loader-diamond-1 1.9s linear infinite;
}
.loader-3d.variant-diamond .ring-2 {
  display: block;
  inset: 11px;
  border-radius: 4px;
  border-color: var(--accent);
  animation: loader-diamond-2 1.5s linear infinite reverse;
}

@keyframes loader-plate-spin {
  from { transform: rotateX(72deg) rotateZ(0deg); }
  to   { transform: rotateX(72deg) rotateZ(360deg); }
}
@keyframes loader-orbit-1 {
  from { transform: rotateX(58deg) rotateY(0deg); }
  to   { transform: rotateX(58deg) rotateY(360deg); }
}
@keyframes loader-orbit-2 {
  from { transform: rotateY(58deg) rotateX(0deg); }
  to   { transform: rotateY(58deg) rotateX(360deg); }
}
@keyframes loader-diamond-1 {
  from { transform: rotate(45deg) rotateX(0deg) rotateY(0deg); }
  to   { transform: rotate(45deg) rotateX(360deg) rotateY(360deg); }
}
@keyframes loader-diamond-2 {
  from { transform: rotate(45deg) rotateY(0deg) rotateX(0deg); }
  to   { transform: rotate(45deg) rotateY(360deg) rotateX(360deg); }
}
.loading-title {
  font-weight: 700; font-size: 15px; margin-bottom: 6px; min-height: 1.3em;
}
/* Minimal typewriter cursor, only shown while the title is actively typing
   (see the .typing class toggled in dashboard.html's setLoadingCopy). */
.loading-title.typing::after {
  content: '';
  display: inline-block;
  width: 1px;
  height: 0.95em;
  margin-left: 2px;
  background: currentColor;
  vertical-align: -0.1em;
  animation: loading-cursor-blink 0.8s steps(1) infinite;
}
@keyframes loading-cursor-blink { 50% { opacity: 0; } }
.loading-sub {
  color: #777; font-size: 12.5px; line-height: 1.5;
  opacity: 0; transition: opacity 0.4s ease;
}
.loading-sub.visible { opacity: 1; }
