/* ==========================================================================
   Synergy — design system stylesheet
   --------------------------------------------------------------------------
   Drop-in for any new app under the Synergy brand. Extracted from the
   original Synergy app (app/templates/base.html) and generalized: the only
   change of substance is that the centered column is a `.shell` class here
   rather than being baked into `body`, so a new app can lay itself out
   however it likes without giving up the rest.

   Usage:
       <link rel="stylesheet" href="synergy.css">
   with assets/InterVariable.woff2 reachable at the url() below.

   The palette is sampled from the logo itself. If the logo ever changes,
   the `--brand-*` block is the other half of the job.
   ========================================================================== */

/* --- Type ---------------------------------------------------------------
   Inter, self-hosted. One variable file covers every weight — never load it
   from a CDN, the original app is deliberately offline-only and the habit is
   worth keeping. */
@font-face {
  font-family: "InterVariable";
  src: url("assets/InterVariable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   1. Tokens
   ========================================================================== */

:root {
  /* Brand. --brand is the mark's DEEPEST blue rather than its mid tone on
     purpose: it colours links and button text, and the brighter tones don't
     clear 4.5:1 against white. The bright end still gets used, but only
     decoratively (gradients, glows), where 3:1 is the bar. */
  --brand: #1766e6;         /* mark gradient, dark end — 5.1:1 on white */
  --brand-dark: #0f52c0;    /* hover / active */
  --brand-bright: #4a8df8;  /* mark gradient, light end — decorative only */
  --brand-ink: #042965;     /* the wordmark navy — headings */
  --brand-pale: #b0cffe;    /* the mark's inner streams */
  --brand-tint: #eaf1fe;
  --brand-tint-2: #e4edfd;
  /* Focus rings and translucent brand washes need the channels separately,
     so they can't just reference --brand. */
  --brand-rgb: 23, 102, 230;

  /* Neutrals, deliberately blue-leaning — ink, muted and borders all sit a
     few degrees toward the brand hue, so even the grey parts of a page feel
     like the same object as the logo. */
  --ink: #1d2433;
  --muted: #5b6474;
  --page-bg: #f4f6fa;
  --surface: #ffffff;
  --surface-2: #fafbfd;
  --surface-3: #eef2f6;
  --ink-soft: #444444;
  --line: var(--border);
  --border: #e4e8f0;
  --border-input: #c6cdda;
  --border-hover: #aab4c6;
  --border-strong: #c8dbfb;

  /* Status */
  --success-bg: #e3f5e3; --success-border: #4a4; --success-ink: #1a5e1a;
  --warn-bg: #fff6e0;    --warn-border: #d9a300; --warn-ink: #8a6d00;
  --error-bg: #fbe4e4;   --error-border: #d33;   --error-ink: #822;
  --danger: #c0392b;     --danger-dark: #a02a1e;
  --danger-border-soft: #e3b3b3; --danger-wash: #fbe9e9;

  /* Button inks as tokens: dark mode's primary blue goes LIGHT, so its
     label must flip dark -- a literal #fff can't. */
  --btn-ink: #ffffff;
  --btn-secondary-bg: #eef0f3; --btn-secondary-ink: #333333;
  --btn-secondary-hover: #e1e4e9;

  /* The green "all good" icon tile. */
  --icon-good-bg: #e6f4ea; --icon-good-ink: #2a9d3a;

  /* Translucent chrome: the nav pill, the auth panel, the busy overlay,
     a tutorial-style scrim, and the login-transition seam cover. */
  --glass-bg: rgba(255, 255, 255, 0.72);
  --glass-border: rgba(228, 232, 240, 0.9);
  --glass-panel-bg: rgba(255, 255, 255, 0.78);
  --glass-panel-border: rgba(255, 255, 255, 0.9);
  --overlay-bg: rgba(246, 248, 252, 0.72);
  --scrim: rgba(13, 32, 74, 0.45);
  --seam: #ffffff;

  /* The hero's whole gradient as one token -- dark mode deepens it. */
  --hero-grad: linear-gradient(135deg, var(--brand-dark) 0%, var(--brand) 50%, var(--brand-bright) 100%);

  /* Theme-conditional display switches (dark block flips them). */
  --show-in-light: block; --show-in-dark: none;

  /* Native form controls and scrollbars follow. */
  color-scheme: light;

  /* The atmosphere's two SVG layers as whole url() tokens, so the dark
     block can swap the entire image. */
  --bg-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  --bg-streams: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1400' height='700' viewBox='0 0 1400 700' fill='none'%3E%3Cpath d='M-40 80 C 320 140, 640 300, 1020 348' stroke='rgb(23,102,230)' stroke-opacity='0.055' stroke-width='2.5'/%3E%3Cpath d='M-40 320 C 340 330, 660 340, 1020 352' stroke='rgb(23,102,230)' stroke-opacity='0.045' stroke-width='2'/%3E%3Cpath d='M-40 600 C 320 540, 640 400, 1020 356' stroke='rgb(23,102,230)' stroke-opacity='0.055' stroke-width='2.5'/%3E%3Cpath d='M1020 352 H 1240' stroke='rgb(23,102,230)' stroke-opacity='0.08' stroke-width='3' stroke-linecap='round'/%3E%3Cpath d='M1196 322 L 1244 352 L 1196 382' stroke='rgb(23,102,230)' stroke-opacity='0.08' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

  /* Categorical series — for charts, chips, calendars. Brand blue leads. */
  --series-1: #1766e6;
  --series-2: #2a9d3a;
  --series-3: #a5540b;
  --series-4: #7b4bab;
  --series-5: #0f7c8a;
  --series-6: #b03060;

  --radius-sm: 8px;
  --radius: 12px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-pill: 999px;

  /* Layered, blue-tinted elevation: a tight contact line plus a soft falloff
     reads far more "product" than one blurry drop shadow. */
  --shadow-sm: 0 1px 2px rgba(13, 32, 74, 0.06);
  --shadow-md: 0 2px 4px rgba(13, 32, 74, 0.05), 0 12px 28px -10px rgba(13, 32, 74, 0.12);
  --shadow-lg: 0 4px 10px rgba(13, 32, 74, 0.06), 0 24px 50px -16px rgba(13, 32, 74, 0.18);

  --text-xs: 0.75rem;
  --text-sm: 0.85rem;
  --text-base: 1rem;
  --text-lg: 1.1rem;
  --text-xl: 1.35rem;
  --text-2xl: 1.7rem;

  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* ==========================================================================
   1b. Dark theme
   --------------------------------------------------------------------------
   Same tokens, navy-leaning values derived from the brand. The block
   appears TWICE because this is plain CSS: once under the device
   preference for users who never chose (guarded so an explicit
   data-theme="light" beats a dark OS), once under data-theme="dark" so a
   toggle beats a light OS. Keep the two copies identical -- the app's
   base.html writes this block once as a Jinja set-block and is the
   source of truth.

   Also note --bg-grain / --bg-streams: the app's atmosphere swaps its two
   data-URI SVG layers per theme this way (a CSS variable can't reach
   inside a data URI, so the whole url() is the token).
   ========================================================================== */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
  --page-bg: #0b1120;
  --surface: #111a2e;
  --surface-2: #16213a;
  --surface-3: #1c2947;
  --ink: #dbe4f5;
  --ink-soft: #c3cde2;
  --muted: #93a1bd;
  --brand: #6ba3fa;
  --brand-dark: #85b4fb;      /* hover goes LIGHTER on a dark ground */
  --brand-bright: #4a8df8;
  --brand-ink: #b0cffe;       /* the mark's streams */
  --brand-rgb: 107, 163, 250;
  --brand-tint: #182b52;
  --brand-tint-2: #1b3059;
  --border: #263352;
  --border-input: #33436b;
  --border-strong: #2f4a7d;
  --border-hover: #4a5b82;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45);
  --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.4), 0 12px 28px -10px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 4px 10px rgba(0, 0, 0, 0.45), 0 24px 50px -16px rgba(0, 0, 0, 0.65);
  --success-bg: #0f2b18; --success-border: #2e7d43; --success-ink: #7fd692;
  --warn-bg: #2f2508; --warn-border: #7a6217; --warn-ink: #e8c464;
  --error-bg: #331116; --error-border: #a94b52; --error-ink: #f2a6ab;
  --danger: #e5726f; --danger-dark: #f08f8c;
  --danger-border-soft: #6b3238; --danger-wash: #3a181c;
  --btn-ink: #0a1730;
  --btn-secondary-bg: #223052; --btn-secondary-ink: #dbe4f5;
  --btn-secondary-hover: #2a3a63;
  --icon-good-bg: #12301c; --icon-good-ink: #5cc474;
  --glass-bg: rgba(17, 26, 46, 0.72);
  --glass-border: rgba(59, 76, 116, 0.6);
  --glass-panel-bg: rgba(17, 26, 46, 0.8);
  --glass-panel-border: rgba(76, 97, 143, 0.5);
  --overlay-bg: rgba(7, 11, 22, 0.72);
  --scrim: rgba(0, 0, 0, 0.62);
  --seam: #0b1120;
  --hero-grad: linear-gradient(135deg, #0a3a8c 0%, #1258c9 50%, #3576e8 100%);
  --show-in-light: none; --show-in-dark: block;
  color-scheme: dark;
  --bg-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.04 0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  --bg-streams: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1400' height='700' viewBox='0 0 1400 700' fill='none'%3E%3Cpath d='M-40 80 C 320 140, 640 300, 1020 348' stroke='rgb(107,163,250)' stroke-opacity='0.055' stroke-width='2.5'/%3E%3Cpath d='M-40 320 C 340 330, 660 340, 1020 352' stroke='rgb(107,163,250)' stroke-opacity='0.045' stroke-width='2'/%3E%3Cpath d='M-40 600 C 320 540, 640 400, 1020 356' stroke='rgb(107,163,250)' stroke-opacity='0.055' stroke-width='2.5'/%3E%3Cpath d='M1020 352 H 1240' stroke='rgb(107,163,250)' stroke-opacity='0.08' stroke-width='3' stroke-linecap='round'/%3E%3Cpath d='M1196 322 L 1244 352 L 1196 382' stroke='rgb(107,163,250)' stroke-opacity='0.08' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  }
}

:root[data-theme="dark"] {
  --page-bg: #0b1120;
  --surface: #111a2e;
  --surface-2: #16213a;
  --surface-3: #1c2947;
  --ink: #dbe4f5;
  --ink-soft: #c3cde2;
  --muted: #93a1bd;
  --brand: #6ba3fa;
  --brand-dark: #85b4fb;      /* hover goes LIGHTER on a dark ground */
  --brand-bright: #4a8df8;
  --brand-ink: #b0cffe;       /* the mark's streams */
  --brand-rgb: 107, 163, 250;
  --brand-tint: #182b52;
  --brand-tint-2: #1b3059;
  --border: #263352;
  --border-input: #33436b;
  --border-strong: #2f4a7d;
  --border-hover: #4a5b82;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45);
  --shadow-md: 0 2px 4px rgba(0, 0, 0, 0.4), 0 12px 28px -10px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 4px 10px rgba(0, 0, 0, 0.45), 0 24px 50px -16px rgba(0, 0, 0, 0.65);
  --success-bg: #0f2b18; --success-border: #2e7d43; --success-ink: #7fd692;
  --warn-bg: #2f2508; --warn-border: #7a6217; --warn-ink: #e8c464;
  --error-bg: #331116; --error-border: #a94b52; --error-ink: #f2a6ab;
  --danger: #e5726f; --danger-dark: #f08f8c;
  --danger-border-soft: #6b3238; --danger-wash: #3a181c;
  --btn-ink: #0a1730;
  --btn-secondary-bg: #223052; --btn-secondary-ink: #dbe4f5;
  --btn-secondary-hover: #2a3a63;
  --icon-good-bg: #12301c; --icon-good-ink: #5cc474;
  --glass-bg: rgba(17, 26, 46, 0.72);
  --glass-border: rgba(59, 76, 116, 0.6);
  --glass-panel-bg: rgba(17, 26, 46, 0.8);
  --glass-panel-border: rgba(76, 97, 143, 0.5);
  --overlay-bg: rgba(7, 11, 22, 0.72);
  --scrim: rgba(0, 0, 0, 0.62);
  --seam: #0b1120;
  --hero-grad: linear-gradient(135deg, #0a3a8c 0%, #1258c9 50%, #3576e8 100%);
  --show-in-light: none; --show-in-dark: block;
  color-scheme: dark;
  --bg-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.04 0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  --bg-streams: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1400' height='700' viewBox='0 0 1400 700' fill='none'%3E%3Cpath d='M-40 80 C 320 140, 640 300, 1020 348' stroke='rgb(107,163,250)' stroke-opacity='0.055' stroke-width='2.5'/%3E%3Cpath d='M-40 320 C 340 330, 660 340, 1020 352' stroke='rgb(107,163,250)' stroke-opacity='0.045' stroke-width='2'/%3E%3Cpath d='M-40 600 C 320 540, 640 400, 1020 356' stroke='rgb(107,163,250)' stroke-opacity='0.055' stroke-width='2.5'/%3E%3Cpath d='M1020 352 H 1240' stroke='rgb(107,163,250)' stroke-opacity='0.08' stroke-width='3' stroke-linecap='round'/%3E%3Cpath d='M1196 322 L 1244 352 L 1196 382' stroke='rgb(107,163,250)' stroke-opacity='0.08' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ==========================================================================
   2. Base + page atmosphere
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

/* Four layers, top to bottom: a whisper of photographic grain (it kills the
   "flat vector app" feel at 5% alpha), the brand's converging-streams line
   art echoing the logo mark — three paths merging into one arrow, the
   product's whole story drawn once at the edge of visibility — and two
   radial brand washes.

   NOTE: the two inline SVGs hardcode rgb(23,102,230); CSS variables cannot
   reach inside a data URI. If the palette changes, change them here too. */
html {
  background-color: var(--page-bg);
  background-image:
    var(--bg-grain),
    var(--bg-streams),
    radial-gradient(1300px 600px at 50% -240px, rgba(var(--brand-rgb), 0.10), transparent 70%),
    radial-gradient(900px 500px at 108% 112%, rgba(74, 141, 248, 0.07), transparent 68%);
  background-repeat: repeat, no-repeat, no-repeat, no-repeat;
  background-position: 0 0, center 18vh, center top, right bottom;
  background-attachment: fixed;
  min-height: 100%;
}

body {
  margin: 0;
  font-family: "InterVariable", system-ui, sans-serif;
  font-optical-sizing: auto;
  font-size: var(--text-base);
  color: var(--ink);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

/* Two soft ambient blobs drifting almost imperceptibly behind the content —
   the "alive" layer of the background. Fixed so they never scroll; z-index
   -1 keeps them behind everything. Opt in with <body class="has-ambient">. */
.has-ambient::before, .has-ambient::after {
  content: "";
  position: fixed;
  width: 440px;
  height: 440px;
  border-radius: 50%;
  z-index: -1;
  pointer-events: none;
  filter: blur(64px);
  animation: ambient-drift 36s ease-in-out infinite alternate;
}
.has-ambient::before {
  top: -180px; left: -140px;
  background: radial-gradient(closest-side, rgba(var(--brand-rgb), 0.10), transparent);
}
.has-ambient::after {
  bottom: -200px; right: -160px;
  background: radial-gradient(closest-side, rgba(74, 141, 248, 0.09), transparent);
  animation-delay: -18s;
}
@keyframes ambient-drift {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(46px, 34px) scale(1.12); }
}

/* --- The column ---------------------------------------------------------
   Synergy is a narrow, centered, single-column product. Three widths, and
   that is the whole layout system — resist adding a fourth. */
.shell        { max-width: 480px; margin: 60px auto; padding: 0 20px; }
.shell--wide  { max-width: 760px; margin-top: 44px; }   /* work surfaces */
.shell--settings { max-width: 720px; }                  /* settings, tables */

/* ==========================================================================
   3. Typography
   ========================================================================== */

h1 { font-size: 1.45rem; font-weight: 700; letter-spacing: -0.02em; color: var(--brand-ink); line-height: 1.2; }
h2, h3 { color: var(--brand-ink); font-weight: 650; letter-spacing: -0.01em; }
h2 { font-size: var(--text-xl); }
h3 { font-size: var(--text-lg); }

/* Tracked-caps section label — the utility voice of the type system. Used as
   an "eyebrow" over cards and groups. */
.overline {
  font-size: var(--text-xs);
  font-weight: 650;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.muted { color: var(--muted); font-size: 0.9rem; }

a { color: var(--brand); text-decoration: none; transition: color 0.15s ease; }
a:hover { color: var(--brand-dark); text-decoration: underline; }

/* Anything counting, timing or tabulating gets lining figures so digits
   don't jitter as they change. */
.tabular { font-variant-numeric: tabular-nums; }

/* ==========================================================================
   4. Forms
   ========================================================================== */

form { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
label { font-size: 0.9rem; font-weight: 600; }

input, select, textarea {
  padding: 10px 12px;
  font-size: 1rem;
  font-family: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-sm);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input:hover, select:hover, textarea:hover { border-color: var(--border-hover); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.15);
}

/* Radio / checkbox option lists — quiet bordered rows instead of naked
   inputs, so a set of choices reads as a group. */
.choice-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.choice {
  display: flex; align-items: baseline; gap: 9px;
  padding: 8px 11px;
  font-weight: 400; font-size: 0.95rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.choice:hover { border-color: var(--border-strong); background: var(--brand-tint); }
.choice input { flex: none; width: auto; transform: translateY(1px); }

/* ==========================================================================
   5. Buttons
   ========================================================================== */

/* Primary buttons carry a faint top sheen over the brand blue. The
   background-COLOR is what hover/active swap, so the sheen survives. */
button, .btn {
  display: inline-block;
  padding: 10px 16px;
  font-size: 1rem;
  font-family: inherit;
  font-weight: 600;
  letter-spacing: 0.005em;
  text-align: center;
  text-decoration: none;
  border: none;
  border-radius: var(--radius-sm);
  background-color: var(--brand);
  background-image: linear-gradient(180deg, rgba(255,255,255,0.16), rgba(255,255,255,0) 55%);
  color: var(--btn-ink);
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.15), 0 1px 2px rgba(13,32,74,0.18);
  transition: background-color 0.15s ease, box-shadow 0.15s ease, transform 0.1s ease;
}
button:hover, .btn:hover {
  background-color: var(--brand-dark);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.15), 0 4px 12px -2px rgba(var(--brand-rgb), 0.45);
  transform: translateY(-1px);
  text-decoration: none;
}
button:active, .btn:active {
  transform: translateY(1px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.1), 0 1px 2px rgba(13,32,74,0.15);
}
button:focus-visible, .btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.35);
}
button:disabled, .btn[aria-disabled="true"] {
  opacity: 0.55; cursor: not-allowed; transform: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.15);
}

/* Muted secondary action, sitting next to a primary. */
.btn-secondary { background: var(--btn-secondary-bg); background-image: none; color: var(--btn-secondary-ink); box-shadow: none; }
.btn-secondary:hover { background: var(--btn-secondary-hover); box-shadow: none; }

/* Destructive. Same filled/darken-on-hover mechanism, just in red. */
.btn-danger { background: var(--danger); }
.btn-danger:hover { background: var(--danger-dark); }

/* The "add another one" affordance: dashed, transparent, brand-coloured.
   Always additive, never destructive, never primary. */
.btn-add {
  width: auto; align-self: flex-start;
  background: transparent; background-image: none; color: var(--brand);
  border: 1px dashed var(--border-strong);
  box-shadow: none; font-size: 0.9rem; padding: 6px 12px;
}
.btn-add:hover { background: var(--brand-tint); box-shadow: none; transform: none; }

/* Quiet backwards move — solid hairline rather than dashed, so it doesn't
   get mistaken for an "add". */
.btn-back {
  width: auto; padding: 5px 12px; font-size: 0.88rem;
  background: transparent; background-image: none; color: var(--brand);
  border: 1px solid var(--border-strong); box-shadow: none;
}
.btn-back:hover { background: var(--brand-tint); box-shadow: none; transform: none; }

/* ==========================================================================
   6. Surfaces
   ========================================================================== */

/* Use `.card` for a static panel; add `.card--link` (or apply to an <a>) for
   the clickable hover-lift variant. */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
}
a.card, .card--link { color: inherit; text-decoration: none; display: block; }
a.card:hover, .card--link:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
  border-color: var(--border-strong);
  text-decoration: none;
}

/* Padded wrapper for forms and content blocks. */
.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px 22px;
  box-shadow: var(--shadow-md);
}
.panel > h1:first-child, .panel > h2:first-child { margin-top: 0; }
.panel form { margin-top: 14px; }

/* Glass over the atmospheric background rather than flat white. Reserved for
   the one panel that is the whole point of its page — a login card, a modal. */
.panel--glass {
  background: var(--glass-panel-bg);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
  border: 1px solid var(--glass-panel-border);
  box-shadow: var(--shadow-lg);
}

/* The mark on the hero, bare -- the white tile that used to back it is
   gone (matching the app). The mark is a disc, so it gets its own circle
   and a soft DARK drop shadow for separation from the same-family blue
   behind it; deliberately no white ring. */
.hero-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.hero-mark img, .hero-mark svg {
  width: 100%;
  height: 100%;
  display: block;
  border-radius: 50%;
  box-shadow: 0 4px 14px -4px rgba(4, 20, 60, 0.55);
}

/* Icon tile — a rounded square of brand tint holding a 20–22px stroke icon
   or a single initial. The workhorse of every list row and settings card. */
.ic {
  flex: none;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  background: var(--brand-tint);
  color: var(--brand);
  border-radius: var(--radius);
  font-size: 1.05rem; font-weight: 650;
}
.ic svg { width: 22px; height: 22px; }
.ic--sm { width: 40px; height: 40px; }
.ic--sm svg { width: 20px; height: 20px; }
.ic--success { background: var(--icon-good-bg); color: var(--icon-good-ink); }

/* Row: icon tile, text stack, chevron. Every navigational list item.
   Selector doubled up because `a.card` above sets display:block at two
   points of specificity — a bare `.row-link` loses to it and the row
   silently stacks. */
.row-link, a.card.row-link, .card.row-link {
  display: flex; align-items: center; gap: 14px; padding: 14px 18px;
}
.row-link .txt { flex: 1; min-width: 0; }
.row-link .txt strong { display: block; color: var(--brand-ink); }
.row-link .txt span { display: block; font-size: var(--text-sm); color: var(--muted); margin-top: 1px; }
.row-link .chev {
  flex: none; color: #c2c8d4; font-size: 1.4rem; line-height: 1;
  transition: transform 0.15s ease, color 0.15s ease;
}
.row-link:hover .chev { transform: translateX(3px); color: var(--brand); }

/* Hub grid of cards. */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
  margin-top: 20px;
}

/* ==========================================================================
   7. Hero
   ========================================================================== */

/* The gradient runs the same dark → mid → bright sweep as the logo mark's
   own, so a white tile sitting on it looks like part of the surface. */
.hero {
  padding: 24px 26px;
  border-radius: var(--radius-lg);
  background: var(--hero-grad);
  color: #fff;
  box-shadow: var(--shadow-md);
  display: flex;
  align-items: center;
  gap: 18px;
}
.hero .hero-mark { width: 56px; height: 56px; }
.hero h1 { color: #fff; font-size: 1.65rem; margin: 0; }
.hero p { margin: 6px 0 0; color: rgba(255,255,255,0.88); font-size: 0.98rem; }

/* Once the page has real work on it, the greeting steps back. */
.hero--compact { padding: 18px 22px; }
.hero--compact .hero-mark { width: 46px; height: 46px; }
.hero--compact h1 { font-size: 1.3rem; }
.hero--compact p { font-size: 0.92rem; margin-top: 3px; }

@media (max-width: 460px) {
  .hero { flex-direction: column; align-items: flex-start; gap: 12px; }
}

/* ==========================================================================
   8. Corner nav — a floating glass pill, not loose icons, so it reads as one
   deliberate object against the atmospheric background.
   ========================================================================== */

.corner-nav-bar {
  position: fixed;
  top: 12px; left: 14px;
  display: flex; align-items: center; gap: 4px;
  padding: 5px 7px;
  border-radius: var(--radius-pill);
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  backdrop-filter: blur(12px) saturate(1.4);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-sm);
  z-index: 500;
}
.corner-nav-bar a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: var(--radius-pill);
  color: #8a93a5;
  text-decoration: none;
  transition: color 0.15s ease, background 0.15s ease;
}
.corner-nav-bar a:hover { color: var(--brand); background: var(--brand-tint); text-decoration: none; }
.corner-nav-bar svg { width: 19px; height: 19px; display: block; }
/* The logo leads the bar — slightly larger than the line icons beside it (a
   filled mark needs the room to read), separated by a hairline so it
   registers as identity rather than a third destination. */
.corner-nav-bar .brand { margin-right: 4px; padding-right: 8px; border-right: 1px solid var(--border); border-radius: 0; }
.corner-nav-bar .brand img { width: 25px; height: 25px; display: block; }
.corner-nav-bar .brand:hover { background: transparent; }

/* ==========================================================================
   9. Progress — the step rail and the bar
   ========================================================================== */

/* The step rail draws the work's real sequence as the brand's converging
   line: each completed stage fills its connector as work flows to the end. */
.steps { display: flex; list-style: none; margin: 0; padding: 0; }
.step { display: flex; align-items: center; flex: 1; }
.step:last-child { flex: 0; }
.step .dot {
  flex: none;
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 2px solid var(--border-input);
  background: var(--surface);
  font-size: 11px; font-weight: 650;
  color: var(--muted);
  transition: background 0.25s ease, border-color 0.25s ease, color 0.25s ease, box-shadow 0.25s ease;
}
.step .lbl {
  margin-left: 8px;
  font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.02em;
  color: var(--muted);
  white-space: nowrap;
  transition: color 0.25s ease;
}
.step .line {
  flex: 1; height: 2px; margin: 0 10px;
  border-radius: 1px; background: var(--border);
  position: relative; overflow: hidden;
}
.step .line::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--brand), var(--brand-bright));
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.4s var(--ease);
}
.step.done .line::after { transform: scaleX(1); }
.step.done .dot { background: var(--brand); border-color: var(--brand); color: #fff; }
.step.active .dot { border-color: var(--brand); color: var(--brand); box-shadow: 0 0 0 4px rgba(var(--brand-rgb), 0.13); }
.step.done .lbl, .step.active .lbl { color: var(--brand-ink); }

.progress-track {
  width: min(320px, 100%); height: 8px;
  background: var(--brand-tint-2);
  border-radius: 6px; overflow: hidden;
  box-shadow: inset 0 1px 2px rgba(13, 32, 74, 0.08);
}
.progress-fill {
  height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--brand) 0%, var(--brand-bright) 100%);
  border-radius: 6px;
  transition: width 0.3s ease-out;
}

.spinner {
  width: 40px; height: 40px;
  border: 3px solid var(--border-strong);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
.spinner--sm { width: 10px; height: 10px; border-width: 2px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Full-screen busy state — frosted, never opaque, so the page underneath
   stays legible as context. */
.overlay-busy {
  position: fixed; inset: 0;
  display: none;
  background: var(--overlay-bg);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
  z-index: 1000;
  align-items: center; justify-content: center; flex-direction: column; gap: 14px;
}
.overlay-busy.visible { display: flex; animation: overlay-in 0.25s ease-out both; }
@keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }

/* ==========================================================================
   10. Status
   ========================================================================== */

.alert { padding: 8px 10px; border-radius: var(--radius-sm); font-size: 0.9rem; border: 1px solid; }
.alert-error   { background: var(--error-bg);   border-color: var(--error-border);   color: var(--error-ink); }
.alert-success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-ink); }
.alert-warn    { background: var(--warn-bg);    border-color: var(--warn-border);    color: var(--warn-ink); }

.pill {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: 600;
}
.pill-brand   { background: var(--brand-tint);  color: var(--brand-dark); }
.pill-success { background: var(--success-bg);  color: var(--success-ink); }
.pill-warn    { background: var(--warn-bg);     color: var(--warn-ink); }
.pill-error   { background: var(--error-bg);    color: var(--error-ink); }

/* An outcome, one per line: tinted row, coloured border, a dot that carries
   the state at a glance. */
.result-item {
  display: flex; gap: 10px; align-items: baseline;
  padding: 12px 14px;
  border-radius: var(--radius);
  border: 1px solid;
}
.result-item .dot { flex: none; width: 9px; height: 9px; border-radius: 50%; transform: translateY(-1px); }
.result-saved  { background: var(--success-bg); border-color: var(--success-border); }
.result-saved .dot { background: #2a9d3a; }
.result-warn   { background: var(--warn-bg);    border-color: var(--warn-border); }
.result-warn .dot { background: #d9a300; }
.result-failed { background: var(--error-bg);   border-color: var(--error-border); }
.result-failed .dot { background: #d33; }

/* ==========================================================================
   11. Motion
   ========================================================================== */

/* Entrance motion, deliberately short (<= 350ms) — this is a tool people use
   all day, and anything longer becomes a tax. Stagger children with
   .reveal-stagger. */
@keyframes fade-up {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.reveal { animation: fade-up 0.32s var(--ease) both; }
.reveal-stagger > * { animation: fade-up 0.32s var(--ease) both; }
.reveal-stagger > *:nth-child(2) { animation-delay: 60ms; }
.reveal-stagger > *:nth-child(3) { animation-delay: 120ms; }
.reveal-stagger > *:nth-child(4) { animation-delay: 180ms; }
.reveal-stagger > *:nth-child(5) { animation-delay: 240ms; }
.reveal-stagger > *:nth-child(n+6) { animation-delay: 300ms; }

/* Freeze every animation and transition app-wide. Spinners stop (their
   percent text still tells the story) and entrance reveals render settled.
   Any JS-driven animation must check the same media query itself. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
