/* ============================================================
   ProjectY — App shell & design system
   Light interface built on a five-colour brand palette: Almond
   Cream, Dark Amethyst, Burgundy, Indigo Bloom, Lavender Purple.
   Layered on top of CDN Bootstrap 5; only adds what utilities
   cannot express cleanly (shell layout, cards, icon buttons,
   completion ring) plus the Bootstrap colour overrides, since
   Bootstrap's own defaults are blue.

   Colour rule: rules below reference Tier 2 semantic tokens only.
   Raw palette values live in Tier 1 and nowhere else. Translucent
   overlays -- rgba(255,255,255,x) scrims and rgba(0,0,0,x) shadows
   -- are the deliberate exception: they are opacity, not hue.
   ============================================================ */

/* ============================================================
   TIER 1 — Raw palette
   The five brand colours and their derived steps. This is the
   ONLY block allowed to contain colour literals. Nothing in the
   rest of the stylesheet (nor any view) may reference these
   directly — always go through a Tier 2 semantic alias, so the
   palette can be re-cut (or inverted for dark mode) in one place.
   ============================================================ */
:root {
  /* Neutral extremes — not brand colours, but the palette's
     text-on-dark and card-surface anchors. */
  --white: #ffffff;

  /* Almond Cream — warm emphasis surface */
  --cream-100: #faf1e6;
  --cream-200: #f3e6d6;
  --cream: #f1dabf;
  --cream-300: #e0c3a0;

  /* Dark Amethyst — ink and dark chrome.
     The -50/-100/-200 steps are the neutral scale: the canvas, the
     hover wash and the borders all carry a trace of the brand hue
     rather than the cool grey they replace. */
  --amethyst-50: #f7f6fa;
  --amethyst-100: #efedf5;
  --amethyst-200: #e3dfec;
  --amethyst-300: #d2cbe1;
  --amethyst-400: #5b5075;
  --amethyst: #2f195f;
  --amethyst-800: #241348;

  /* Burgundy — primary call to action */
  --burgundy: #890620;
  --burgundy-800: #6b0418;
  --burgundy-100: #f6e6e9;

  /* Indigo Bloom — secondary actions, active UI states */
  --indigo: #5525b5;
  --indigo-800: #451d94;
  --indigo-100: #eee9fa;

  /* Lavender Purple — decorative fills, borders, dots.
     --lavender is a MID-TONE: it clears nothing. White on it is
     3.9:1 and Dark Amethyst on it 3.8:1, both under AA for normal
     text, and --lavender-ink on it is worse still (1.9:1) because
     the two are neighbours on the same ramp. So the base tone is
     never a text background. A lavender badge is built the other
     way round: --lavender-100 fill + --lavender-ink label (6.3:1),
     with --lavender itself left for the border and the dot. */
  --lavender-100: #f2ecfb;
  --lavender: #9b69db;
  --lavender-ink: #6b3fa8;

  /* Categorical scale — a SEPARATE axis from the brand palette above.
     These encode which kind of content a card holds; they are data, so
     they need to stay mutually distinguishable and cannot be folded
     into five brand colours (decision D2a). Both are deepened toward
     the palette's jewel tone, which also fixes a pre-existing
     accessibility bug: the previous #16a34a / #d97706 pair carried
     0.78rem chip text at only 3.3:1 and 3.2:1, under AA. */
  --cat-green: #12794a;
  --cat-amber: #9a5b06;

  /* Destructive red — its own hue, deliberately not Burgundy, and set
     apart from it by lightness rather than family (see --danger). */
  --red: #c2183a;
  --red-800: #9d1330;

  /* Alert tints — subtle fill / border / emphasis ink per intent.
     Bootstrap builds its alerts from a three-part set like this, so
     supplying ours is what re-skins every .alert- variant at once. */
  --tint-success-bg: #e7f3ed;
  --tint-success-border: #bcdccb;
  --tint-success-ink: #0b4d2f;
  --tint-warning-bg: #f9efdf;
  --tint-warning-border: #e6cfa8;
  --tint-warning-ink: #6b3f04;
  --tint-danger-bg: #fdecef;
  --tint-danger-border: #f2c3cd;
  --tint-danger-ink: #8f1129;
  --tint-info-bg: #f2ecfb;
  --tint-info-border: #d9c8f0;
  --tint-info-ink: #4d2b7a;

  /* RGB triplets. Bootstrap composes its utilities as
     rgba(var(--bs-*-rgb), opacity), so it needs channels rather than
     hex — these must be kept in sync with the hex values above by
     hand, since CSS cannot decompose a custom property. */
  --indigo-rgb: 85, 37, 181;
  --amethyst-rgb: 47, 25, 95;
  --amethyst-400-rgb: 91, 80, 117;
  --burgundy-rgb: 137, 6, 32;
  --cream-100-rgb: 250, 241, 230;
  --cat-green-rgb: 18, 121, 74;
  --cat-amber-rgb: 154, 91, 6;
  --danger-rgb: 194, 24, 58;
  --lavender-ink-rgb: 107, 63, 168;
}

/* ============================================================
   TIER 2 — Semantic aliases
   What the UI actually speaks: surfaces, ink, borders, intent.
   ============================================================ */
:root {
  /* Surfaces. Per decision D1(b) the canvas stays a near-neutral —
     a faint amethyst wash, not Almond Cream. Cream is reserved for
     emphasis surfaces (--surface-warm), which is what keeps it
     reading as emphasis instead of as the product's base colour. */
  --shell-bg: var(--amethyst-50);
  --surface: var(--white);
  --surface-alt: var(--cream-100);
  --surface-alt-hover: var(--cream-200);
  --surface-hover: var(--amethyst-100);
  --surface-warm: var(--cream);
  --surface-warm-hover: var(--cream-300);
  --sidebar-bg: var(--surface);

  /* Borders */
  --border: var(--amethyst-200);
  --border-strong: var(--amethyst-300);
  --border-warm: var(--cream-300);

  /* Ink. --text-muted is Dark Amethyst at 400: it clears AA on all
     three surfaces we put it on — 7.3:1 on white, 6.8:1 on the
     canvas, 5.4:1 on cream. The grey it replaces managed only
     3.7:1 on cream. */
  --text: var(--amethyst);
  --text-muted: var(--amethyst-400);
  --text-on-accent: var(--white);
  --text-on-cta: var(--white);

  /* Accent — secondary actions, active states, links */
  --accent: var(--indigo);
  --accent-rgb: 85, 37, 181;
  --accent-soft: var(--indigo-100);
  --accent-strong: var(--indigo-800);

  /* CTA — the one committing action per screen. */
  --cta: var(--burgundy);
  --cta-strong: var(--burgundy-800);
  --cta-soft: var(--burgundy-100);
  --cta-rgb: 137, 6, 32;

  /* Saved / favourite. Burgundy, not a red of its own: the filled
     hearts are the loudest colour in the library grid, and the rose
     they used to be was the single worst clash with the purples.
     A state mark, not a control — it does not spend the CTA's
     scarcity. Reversible on this one line if it proves too heavy. */
  --saved: var(--burgundy);

  /* Destructive / alert — deliberately NOT Burgundy, so "delete" never
     wears the same colour as "enregistrer". It is separated from the
     CTA by lightness (a mid red against a near-black maroon) because
     they do co-occur: the parameters overlay stacks a primary submit
     above two destructive controls. */
  --danger: var(--red);
  --danger-strong: var(--red-800);
  --danger-soft: var(--tint-danger-bg);

  /* Focus. Two rings, because one cannot serve both backdrops: Indigo
     Bloom reads at 8.4:1 on the canvas but collapses to 1.6:1 on the
     Dark Amethyst chrome, where cream takes over at 10.9:1. */
  --focus-ring: var(--accent);
  --focus-ring-inverse: var(--cream);

  /* Content-type categorical scale (separate axis from the brand
     palette — these encode data, not hierarchy). Colour is never the
     only channel: every chip and pill carries its type as text too,
     which is what keeps the trio usable under red-green CVD, where
     the green and the amber are the confusable pair. */
  --type-event: var(--cat-green);
  --type-article: var(--accent);
  --type-appel: var(--cat-amber);

  /* Decorative divider on emphasis surfaces */
  --divider-soft: var(--lavender);

  /* Progress sweep — the palette's one gradient */
  --progress-from: var(--indigo);
  --progress-to: var(--lavender);

  /* Soft badge — tint fill, mid-tone edge, dark ink (see --lavender) */
  --badge-bg: var(--lavender-100);
  --badge-border: var(--lavender);
  --badge-ink: var(--lavender-ink);

  /* Landing hero backdrop — Indigo Bloom to Lavender Purple, the same
     sweep as the progress ring, opened out across the viewport. */
  --hero-from: var(--indigo-100);
  --hero-to: var(--lavender-100);

  /* Geometry */
  --sidebar-width: 264px;
  --sidebar-rail: 76px;
  --radius: 14px;
  --radius-sm: 10px;
}

body {
  background-color: var(--shell-bg);
  color: var(--text);
}

/* ============================================================
   Bootstrap theme variables
   Every Bootstrap colour utility resolves through a :root variable
   — .text-muted reads --bs-secondary-color, .bg-primary reads
   rgba(var(--bs-primary-rgb), …), .alert-* read the -bg-subtle /
   -border-subtle / -text-emphasis trio. Redefining that set here
   re-skins roughly fifty utility usages across the views at once,
   instead of rewriting fifty class attributes.

   Note --bs-success / --bs-warning: in this product those two are
   not "success" and "warning" at all. The agenda rows and their
   legend use them to mean *event* and *appel à projet*, so they are
   mapped onto the content-type scale. That was the fourth place the
   type colours were defined.
   ============================================================ */
:root {
  --bs-body-color: var(--text);
  --bs-body-bg: var(--shell-bg);
  --bs-secondary-color: var(--text-muted);
  --bs-border-color: var(--border);

  --bs-primary-rgb: var(--indigo-rgb);
  --bs-secondary-rgb: var(--amethyst-400-rgb);
  --bs-dark-rgb: var(--amethyst-rgb);
  --bs-light-rgb: var(--cream-100-rgb);
  --bs-success-rgb: var(--cat-green-rgb);
  --bs-warning-rgb: var(--cat-amber-rgb);
  --bs-danger-rgb: var(--danger-rgb);
  --bs-info-rgb: var(--lavender-ink-rgb);

  --bs-link-color: var(--accent);
  --bs-link-color-rgb: var(--indigo-rgb);
  --bs-link-hover-color: var(--accent-strong);

  --bs-success-bg-subtle: var(--tint-success-bg);
  --bs-success-border-subtle: var(--tint-success-border);
  --bs-success-text-emphasis: var(--tint-success-ink);
  --bs-warning-bg-subtle: var(--tint-warning-bg);
  --bs-warning-border-subtle: var(--tint-warning-border);
  --bs-warning-text-emphasis: var(--tint-warning-ink);
  --bs-danger-bg-subtle: var(--tint-danger-bg);
  --bs-danger-border-subtle: var(--tint-danger-border);
  --bs-danger-text-emphasis: var(--tint-danger-ink);
  --bs-info-bg-subtle: var(--tint-info-bg);
  --bs-info-border-subtle: var(--tint-info-border);
  --bs-info-text-emphasis: var(--tint-info-ink);
}

/* ---------- Focus visibility ----------
   The custom controls here are <a> and <button> elements that strip
   their own borders and backgrounds, leaving the UA's default ring to
   land on whatever backdrop happens to be behind it. One token-driven
   ring keeps the keyboard path legible and identical across the shell.
   :focus-visible only, so pointer users never see it. */
.sidebar-link:focus-visible,
.sidebar-brand:focus-visible,
.sidebar-collapse-btn:focus-visible,
.btn-icon:focus-visible,
.back-arrow:focus-visible,
.filter-pill:focus-visible,
.filter-dd-toggle:focus-visible,
.content-card:focus-visible,
.agenda-item:focus-visible,
.newsletter-ribbon:focus-visible,
.hero-cta:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
/* On the detail page's dark chrome the indigo ring would disappear. */
.card-header .btn:focus-visible {
  outline: 2px solid var(--focus-ring-inverse);
  outline-offset: 2px;
}

/* Both fills are now dark enough to need light labels; Bootstrap
   ships .btn-warning with near-black text, which would land at
   2.7:1 on the new amber. */
.btn-warning,
.btn-success {
  --bs-btn-color: var(--text-on-accent);
  --bs-btn-hover-color: var(--text-on-accent);
  --bs-btn-active-color: var(--text-on-accent);
}

/* ---------- Bootstrap button overrides ----------
   Two tiers, per the 60-30-10 split. .btn-primary is the committing
   action and wears Burgundy; it is meant to be rare, so anything that
   merely loads more rows or opens a panel uses the Indigo secondary
   instead. Bootstrap's own blue is never allowed through. */
.btn-primary {
  --bs-btn-bg: var(--cta);
  --bs-btn-border-color: var(--cta);
  --bs-btn-color: var(--text-on-cta);
  --bs-btn-hover-bg: var(--cta-strong);
  --bs-btn-hover-border-color: var(--cta-strong);
  --bs-btn-hover-color: var(--text-on-cta);
  --bs-btn-active-bg: var(--cta-strong);
  --bs-btn-active-border-color: var(--cta-strong);
  --bs-btn-active-color: var(--text-on-cta);
  --bs-btn-disabled-bg: var(--cta);
  --bs-btn-disabled-border-color: var(--cta);
  --bs-btn-focus-shadow-rgb: var(--cta-rgb);
}

/* Secondary: "Charger plus", "Plus d'articles", panel toggles. */
.btn-outline-primary {
  --bs-btn-color: var(--accent);
  --bs-btn-border-color: var(--accent);
  --bs-btn-hover-bg: var(--accent);
  --bs-btn-hover-border-color: var(--accent);
  --bs-btn-hover-color: var(--text-on-accent);
  --bs-btn-active-bg: var(--accent-strong);
  --bs-btn-active-border-color: var(--accent-strong);
  --bs-btn-active-color: var(--text-on-accent);
  --bs-btn-disabled-color: var(--accent);
  --bs-btn-disabled-border-color: var(--accent);
  --bs-btn-focus-shadow-rgb: var(--accent-rgb);
}

/* Neutral chrome button ("Ajuster mes préférences", the topbar toggle).
   Bootstrap's .btn-light is a cool grey that reads dirty next to the
   warmer surfaces, so it borrows the card tokens instead. */
.btn-light {
  --bs-btn-bg: var(--surface);
  --bs-btn-border-color: var(--border);
  --bs-btn-color: var(--text);
  --bs-btn-hover-bg: var(--surface-hover);
  --bs-btn-hover-border-color: var(--border-strong);
  --bs-btn-hover-color: var(--text);
  --bs-btn-active-bg: var(--surface-hover);
  --bs-btn-active-border-color: var(--border-strong);
  --bs-btn-active-color: var(--text);
}

/* Destructive. Separated from the CTA by lightness, not hue. */
.btn-danger {
  --bs-btn-bg: var(--danger);
  --bs-btn-border-color: var(--danger);
  --bs-btn-hover-bg: var(--danger-strong);
  --bs-btn-hover-border-color: var(--danger-strong);
  --bs-btn-active-bg: var(--danger-strong);
  --bs-btn-active-border-color: var(--danger-strong);
  --bs-btn-disabled-bg: var(--danger);
  --bs-btn-disabled-border-color: var(--danger);
}
.btn-outline-danger {
  --bs-btn-color: var(--danger);
  --bs-btn-border-color: var(--danger);
  --bs-btn-hover-bg: var(--danger);
  --bs-btn-hover-border-color: var(--danger);
  --bs-btn-active-bg: var(--danger-strong);
  --bs-btn-active-border-color: var(--danger-strong);
  --bs-btn-disabled-color: var(--danger);
  --bs-btn-disabled-border-color: var(--danger);
}
a {
  color: var(--accent);
}

/* ---------- Bootstrap form controls ----------
   Bootstrap ships checkboxes, switches, ranges and every focus ring in
   its own blue and hardcodes those values rather than exposing them as
   variables, so each control has to be named explicitly. Without this
   block the profile form keeps rendering blue checkboxes and a blue
   newsletter switch against a purple product. */
.form-check-input:checked {
  background-color: var(--accent);
  border-color: var(--accent);
}
.form-check-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 0.25rem rgba(var(--accent-rgb), 0.25);
}
/* The switch knob is an SVG carried in a data URI, and a data URI cannot
   read a custom property — so these two are the one place outside Tier 1
   where a palette value is written literally. Keep them in sync with
   --indigo by hand. */
.form-switch .form-check-input:focus {
  --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%235525b5'/%3e%3c/svg%3e");
}
.form-switch .form-check-input:checked {
  --bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e");
}
.form-control:focus,
.form-select:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 0.25rem rgba(var(--accent-rgb), 0.2);
}
.form-range::-webkit-slider-thumb {
  background-color: var(--accent);
}
.form-range::-moz-range-thumb {
  background-color: var(--accent);
}
.form-range::-webkit-slider-runnable-track {
  background-color: var(--border);
}
.form-range::-moz-range-track {
  background-color: var(--border);
}
.form-range:focus::-webkit-slider-thumb {
  box-shadow: 0 0 0 1px var(--surface), 0 0 0 0.25rem rgba(var(--accent-rgb), 0.25);
}
.form-range:focus::-moz-range-thumb {
  box-shadow: 0 0 0 1px var(--surface), 0 0 0 0.25rem rgba(var(--accent-rgb), 0.25);
}

/* ============================================================
   App shell
   ============================================================ */
.app-shell {
  display: flex;
  min-height: 100vh;
}

/* Shared visual styling for both the desktop sidebar and the mobile
   offcanvas. Intentionally NO position/flex here so it never overrides
   Bootstrap's fixed-position offcanvas (which would otherwise reserve a
   phantom column on desktop). */
.app-sidebar {
  width: var(--sidebar-width);
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: 1.25rem 0.875rem;
}

/* Desktop-only: turn the sidebar into a sticky flex column. */
.app-sidebar-fixed {
  flex: 0 0 var(--sidebar-width);
  width: var(--sidebar-width);
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  transition: flex-basis 0.2s ease, width 0.2s ease;
}

.app-main {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  /* Fluid: the content fills the space next to the sidebar. A fixed max-width
     left an empty band on one side on wide screens (centered → gap by the
     sidebar; left-aligned → gap on the right). The 2rem padding keeps edge
     breathing room; the inner Bootstrap grid handles column proportions. */
  padding: 1.75rem 2rem 3rem;
}

@media (max-width: 991.98px) {
  .app-main {
    padding: 1.25rem 1rem 2.5rem;
  }
}

/* ---------- Sidebar brand ---------- */
.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.25rem 0.6rem 1rem;
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--text);
  text-decoration: none;
}
/* The mark is a ~5.6:1 wordmark, not the 28px square icon this box was
   built for: it is sized by height and left to take the width it needs. */
.sidebar-brand img {
  height: 26px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}
.sidebar-brand-topbar img {
  height: 22px;
}
.navbar-brand-logo img {
  height: 28px;
  width: auto;
}

/* ---------- Sidebar navigation ---------- */
.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.sidebar-label {
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 0.75rem 0.6rem 0.35rem;
}
button.sidebar-link {
  width: 100%;
  border: none;
  background: none;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
.sidebar-link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0.65rem;
  border-radius: var(--radius-sm);
  color: var(--text);
  text-decoration: none;
  font-size: 0.925rem;
  font-weight: 500;
  line-height: 1.2;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.sidebar-link i {
  font-size: 1.05rem;
  color: var(--text-muted);
  width: 1.2rem;
  text-align: center;
}
.sidebar-link:hover {
  background: var(--surface-hover);
  color: var(--text);
}
.sidebar-link.active {
  background: var(--accent-soft);
  color: var(--accent-strong);
}
.sidebar-link.active i {
  color: var(--accent);
}

.sidebar-spacer {
  flex: 1 1 auto;
}

/* ---------- Sidebar user block ---------- */
.sidebar-user {
  border-top: 1px solid var(--border);
  padding-top: 0.85rem;
  margin-top: 0.5rem;
}
.sidebar-user-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.25rem 0.6rem 0.6rem;
}
.sidebar-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 34px;
  background: var(--accent);
  color: var(--text-on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 0.85rem;
}
.sidebar-user-name {
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- Mobile top bar ---------- */
.app-topbar {
  display: none;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 1rem;
  background: var(--sidebar-bg);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 1030;
}
@media (max-width: 991.98px) {
  .app-sidebar.app-sidebar-fixed {
    display: none;
  }
  .app-topbar {
    display: flex;
  }
}

/* ============================================================
   Sidebar collapse (desktop) — Notion-style icon rail
   State is driven by `html.sidebar-collapsed`; only the fixed
   desktop sidebar reacts (the mobile offcanvas is unaffected).
   ============================================================ */
.sidebar-collapse-row {
  display: flex;
  justify-content: flex-end;
  padding: 0 0.25rem 0.25rem;
}
.sidebar-collapse-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.sidebar-collapse-btn:hover {
  background: var(--surface-hover);
  color: var(--text);
}
.sidebar-collapse-btn i {
  font-size: 1rem;
  transition: transform 0.2s ease;
}

/* Fade the textual labels in sync with the width transition. */
.app-sidebar-fixed .sidebar-brand img,
.app-sidebar-fixed .sidebar-link span,
.app-sidebar-fixed .sidebar-user-name,
.app-sidebar-fixed .sidebar-label {
  transition: opacity 0.15s ease;
}

/* The mobile offcanvas never collapses, so its content is not hidden here. */
@media (min-width: 992px) {
  html.sidebar-collapsed .app-sidebar-fixed {
    flex-basis: var(--sidebar-rail);
    width: var(--sidebar-rail);
  }
  html.sidebar-collapsed .app-sidebar-fixed .sidebar-collapse-row {
    justify-content: center;
  }
  html.sidebar-collapsed .app-sidebar-fixed .sidebar-collapse-btn i {
    transform: rotate(180deg);
  }
  html.sidebar-collapsed .app-sidebar-fixed .sidebar-brand img,
  html.sidebar-collapsed .app-sidebar-fixed .sidebar-link span,
  html.sidebar-collapsed .app-sidebar-fixed .sidebar-user-name,
  html.sidebar-collapsed .app-sidebar-fixed .sidebar-label {
    opacity: 0;
    pointer-events: none;
  }
  /* The rail is ~48px of usable width; a 5.6:1 wordmark squeezed into it
     would render about 8px tall, so it is dropped rather than shrunk.
     A square glyph variant of the mark would let the rail keep a brand
     presence here — we only have the wordmark today. */
  html.sidebar-collapsed .app-sidebar-fixed .sidebar-brand {
    padding-bottom: 0.5rem;
  }
}

/* ============================================================
   Newsletter inactive ribbon
   ============================================================ */
/* Cream and Burgundy rather than the warn-orange it used to be: this is a
   nudge to finish setting up a newsletter, not a warning that something
   is wrong, and an alert palette overstated it. Burgundy on cream runs
   7.4:1. */
.newsletter-ribbon {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: var(--surface-warm);
  border: 1px solid var(--border-warm);
  color: var(--cta);
  border-radius: var(--radius-sm);
  padding: 0.7rem 1rem;
  margin-bottom: 1.5rem;
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
}
.newsletter-ribbon:hover {
  background: var(--surface-warm-hover);
  color: var(--cta-strong);
}
.newsletter-ribbon i:first-child {
  font-size: 1.1rem;
}
.newsletter-ribbon .ribbon-cta {
  margin-left: auto;
  white-space: nowrap;
  font-weight: 600;
}

/* ============================================================
   Page header
   ============================================================ */
.page-title {
  font-size: 1.9rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0;
}
@media (max-width: 575.98px) {
  .page-title {
    font-size: 1.55rem;
  }
}

/* Back control: a single, subordinate arrow */
.back-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border);
  text-decoration: none;
  font-size: 1.15rem;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.back-arrow:hover {
  background: var(--surface-hover);
  color: var(--text);
}

/* ============================================================
   Icon button (icon-only action)
   ============================================================ */
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.btn-icon:hover {
  background: var(--surface-hover);
  color: var(--text);
}
.btn-icon.is-saved {
  color: var(--saved);
}
.btn-icon.is-read {
  color: var(--type-event);
}

/* ============================================================
   Content filter bar (segmented pills)
   ============================================================ */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 1.5rem;
}
.filter-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  border-radius: 999px;
  padding: 0.38rem 0.85rem;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.12s ease, border-color 0.12s ease,
    color 0.12s ease;
}
.filter-pill:hover {
  border-color: var(--border-strong);
  background: var(--surface-hover);
}
.filter-pill.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
}
.filter-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
}

/* ---------- Lavender badge ----------
   For NON-categorical tags only ("Nouveau", "Pro", counts) — never for
   a content type, which must stay on the categorical scale.
   Built tint-fill + ink-label rather than lavender-fill + light-label:
   the base tone reaches only 3.8:1 against white and 3.9:1 against Dark
   Amethyst, so it cannot sit under small text. Here it is confined to
   the border and the dot, where 3:1 for a non-text boundary is enough,
   and the label runs at 6.3:1. */
.badge-soft {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  background: var(--badge-bg);
  border: 1px solid var(--badge-border);
  color: var(--badge-ink);
  border-radius: 999px;
  padding: 0.15rem 0.55rem;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.4;
}
.badge-soft .filter-dot {
  background: var(--badge-border);
}

/* ---- Library filter toolbar ---- */
.library-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.toolbar-spacer {
  flex: 1 1 auto;
}
.toolbar-sep {
  width: 1px;
  align-self: stretch;
  min-height: 1.5rem;
  background: var(--border);
  margin: 0 0.25rem;
}
.filter-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

/* Category dropdown: click a pill to reveal its checkbox list */
.filter-dd {
  position: relative;
}
.filter-dd-toggle .bi-chevron-down {
  font-size: 0.7rem;
  transition: transform 0.15s ease;
}
.filter-dd.open .filter-dd-toggle .bi-chevron-down {
  transform: rotate(180deg);
}
.filter-dd-toggle.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
}
.filter-dd-count {
  display: inline-block;
  background: var(--accent);
  color: var(--text-on-accent);
  border-radius: 999px;
  font-size: 0.7rem;
  line-height: 1;
  padding: 0.15rem 0.4rem;
  margin-left: 0.35rem;
}
.filter-dd-toggle.active .filter-dd-count {
  background: rgba(255, 255, 255, 0.25);
}
.filter-dd-panel {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  min-width: 220px;
  max-width: 320px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
  padding: 0.75rem;
}
.filter-dd.open .filter-dd-panel {
  display: block;
}
.filter-checks {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  max-height: 260px;
  overflow-y: auto;
  padding-right: 0.25rem;
}
.filter-check {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.88rem;
  cursor: pointer;
  margin: 0;
  white-space: nowrap;
}
.filter-check input {
  cursor: pointer;
  flex-shrink: 0;
}

/* ============================================================
   Content card
   ============================================================ */
.content-card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1rem 1.15rem 1.05rem;
  text-decoration: none;
  color: var(--text);
  transition: box-shadow 0.14s ease, transform 0.14s ease,
    border-color 0.14s ease;
}
.content-card:hover {
  box-shadow: 0 6px 20px rgba(20, 20, 40, 0.08);
  border-color: var(--border-strong);
  transform: translateY(-2px);
  color: var(--text);
}
.content-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.65rem;
}
.type-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-muted);
}
.type-chip .filter-dot {
  width: 9px;
  height: 9px;
}
.type-event {
  color: var(--type-event);
}
.type-article {
  color: var(--type-article);
}
.type-appel {
  color: var(--type-appel);
}
.dot-event {
  background: var(--type-event);
}
.dot-article {
  background: var(--type-article);
}
.dot-appel {
  background: var(--type-appel);
}

.content-date {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 0.3rem;
}
.content-title {
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.3;
  margin: 0 0 0.6rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.content-meta {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.82rem;
  color: var(--text-muted);
  margin-bottom: 0.9rem;
}
.content-card-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
}
.content-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: auto;
}
.seen-flag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.78rem;
  color: var(--type-event);
  font-weight: 500;
}
/* The "Déjà vu" flag only shows once the card is marked read; the eye button
   toggles .is-read on the card for instant optimistic feedback. */
.content-card-foot .seen-flag {
  display: none;
}
.content-card.is-read .content-card-foot .seen-flag {
  display: inline-flex;
}
/* Read toggle in the content detail header (labeled .btn on dark chrome).
   Scoped to .btn so the icon-only .btn-icon variant in cards is unaffected. */
/* Both "active state" buttons on the detail page's Dark Amethyst
   chrome work the same way: a near-white scrim carrying the state's
   own colour. Neither state colour can sit directly on the chrome —
   the categorical green lands at 2.0:1 on Dark Amethyst and Burgundy
   at 1.3:1 — so the light fill is what makes them legible, at 5.4:1
   and 9.9:1 respectively. */
.btn.read-btn.is-read {
  background: rgba(255, 255, 255, 0.92);
  color: var(--type-event);
  border-color: rgba(255, 255, 255, 0.92);
}
.btn.btn-saved {
  background: rgba(255, 255, 255, 0.92);
  color: var(--saved);
  border: 1px solid rgba(255, 255, 255, 0.92);
  font-weight: 600;
}
.btn.btn-saved:hover,
.btn.btn-saved:focus-visible {
  background: var(--surface);
  color: var(--cta-strong);
  border-color: var(--surface);
}
/* keep the save control above the card-wide link */
.content-card .btn-icon {
  position: relative;
  z-index: 2;
}

/* ============================================================
   Dashboard — profile layout
   ============================================================ */
.section-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem 1.25rem 1.35rem;
  height: 100%;
}
.section-card-title {
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 700;
  margin-bottom: 1rem;
}
/* Center column: the newsletter-impacting fields, visually distinguished.
   This is cream's main job under decision D1(b) — the one surface that
   is warm, which is what makes it read as the emphasised one. The wash
   is longer than the old 120px because cream is subtler than the indigo
   tint it replaces. */
.section-newsletter {
  border-left: 4px solid var(--accent);
  background: linear-gradient(180deg, var(--surface-warm) 0%, var(--surface) 180px);
}
.section-newsletter .section-card-title {
  color: var(--text);
}
/* Soft lavender rules inside the emphasis surface, per the palette's
   "borders & dividers on decorated surfaces" role. */
.section-newsletter hr {
  border-color: var(--divider-soft);
  opacity: 0.35;
}

/* ---------- Profile completion ring ---------- */
/* The filled arc sweeps Indigo Bloom -> Lavender Purple: the palette's
   one gradient, spent on the single element that is genuinely about
   progress. The trailing `var(--border) 0` clamps to the previous stop,
   which is what gives the hard edge between arc and track. */
.completion-ring {
  --p: 0;
  --ring: var(--progress-from);
  --ring-end: var(--progress-to);
  width: 132px;
  height: 132px;
  border-radius: 50%;
  margin: 0.25rem auto 1rem;
  display: grid;
  place-items: center;
  background: conic-gradient(
    var(--ring) 0deg,
    var(--ring-end) calc(var(--p) * 3.6deg),
    var(--border) 0
  );
}
.completion-ring__hole {
  width: 102px;
  height: 102px;
  border-radius: 50%;
  background: var(--surface);
  display: grid;
  place-items: center;
  text-align: center;
}
.completion-ring__value {
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1;
  color: var(--text);
}
.completion-ring__label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  margin-top: 0.2rem;
}

.profile-avatar-lg {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--accent);
  color: var(--text-on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  font-weight: 700;
}

/* ============================================================
   Split repartition bar
   ============================================================ */
.split-bar-wrapper {
  position: relative;
  height: 44px;
  display: flex;
  align-items: center;
}
.split-bar-track {
  position: absolute;
  left: 0; right: 0;
  height: 8px;
  border-radius: 4px;
  background: var(--border);
  overflow: hidden;
}
.split-bar-fill {
  position: absolute;
  inset: 0;
  border-radius: 4px;
  transition: background 0.1s linear;
}
.split-bar-thumb {
  position: absolute;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  background: transparent;
  border: none;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
  pointer-events: none;
}
.split-bar-thumb::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent);
  box-shadow: 0 1px 4px rgba(0,0,0,0.18);
  cursor: pointer;
  pointer-events: all;
}
.split-bar-thumb::-moz-range-thumb {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent);
  box-shadow: 0 1px 4px rgba(0,0,0,0.18);
  cursor: pointer;
  pointer-events: all;
}
.split-bar-thumb:focus-visible::-webkit-slider-thumb {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.split-bar-legend {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.6rem;
  font-size: 0.82rem;
  color: var(--text-muted);
}
.split-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 4px;
  vertical-align: middle;
}

/* ---------- Agenda rows — À venir / En cours (Mes enregistrements) ---------- */
.agenda-item {
  background: var(--surface-alt);
  transition: background-color 0.12s ease, transform 0.12s ease;
}
.agenda-item:hover {
  background: var(--surface-alt-hover);
  transform: translateX(2px);
}

/* ============================================================
   Landing page (views/home/index.hbs)
   Lifted out of a <style> block inside the template, where ~30 colour
   literals sat beyond the reach of the token layer — including two
   leaks of Bootstrap's own blue in the mad-libs inputs and the value
   icons, which is why the public page never matched the product.
   ============================================================ */
.hero-section {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: linear-gradient(
    160deg,
    var(--hero-from) 0%,
    var(--surface) 55%,
    var(--hero-to) 100%
  );
  padding: 4rem 1rem;
}
.hero-section img {
  display: block;
}
.hero-tagline {
  font-size: clamp(2rem, 5vw, 3.25rem);
  font-weight: 800;
  color: var(--text);
  line-height: 1.15;
  max-width: 700px;
}
.hero-sub {
  max-width: 520px;
  font-size: 1.05rem;
}
.hero-values {
  max-width: 900px;
  width: 100%;
}

/* The page's one committing action wears the CTA; "Connexion" is the
   quieter twin and takes an outline rather than a second fill. */
.hero-cta {
  background: var(--cta);
  color: var(--text-on-cta);
  border-radius: 50px;
  padding: 0.85rem 2.5rem;
  font-size: 1rem;
  font-weight: 600;
  border: 2px solid var(--cta);
  text-decoration: none;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}
.hero-cta:hover {
  background: var(--cta-strong);
  border-color: var(--cta-strong);
  color: var(--text-on-cta);
}
.hero-cta-secondary {
  background: var(--surface);
  color: var(--text);
  border-color: var(--text);
}
.hero-cta-secondary:hover {
  background: var(--surface-hover);
  border-color: var(--text);
  color: var(--text);
}

/* ---------- Value cards ---------- */
.value-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 2rem 1.5rem;
  text-align: center;
  opacity: 0;
  transform: translateY(30px);
  animation: fadeInUp 0.6s ease forwards;
}
.value-card:nth-child(1) { animation-delay: 0.1s; }
.value-card:nth-child(2) { animation-delay: 0.25s; }
.value-card:nth-child(3) { animation-delay: 0.4s; }
@keyframes fadeInUp {
  to { opacity: 1; transform: translateY(0); }
}
/* Honour a reduced-motion preference: the cards animate in from
   opacity 0, so without this they would simply never appear. */
@media (prefers-reduced-motion: reduce) {
  .value-card {
    animation: none;
    opacity: 1;
    transform: none;
  }
}
.value-icon {
  font-size: 2.25rem;
  color: var(--accent);
  margin-bottom: 1rem;
}
.value-card h5 {
  font-weight: 700;
  color: var(--text);
  margin-bottom: 0.5rem;
}
.value-card p {
  color: var(--text-muted);
  font-size: 0.93rem;
  margin: 0;
}

/* ---------- Try-it section ----------
   The landing page's Almond Cream band — the same emphasis role cream
   plays on the newsletter card, at full width. */
.tryit-section {
  background: var(--surface-warm);
  padding: 5rem 1rem;
}
.tryit-container {
  max-width: 860px;
}
.tryit-section h2 {
  font-size: clamp(1.6rem, 3.5vw, 2.4rem);
  font-weight: 800;
  color: var(--text);
  margin-bottom: 0.5rem;
}
.tryit-section .lead {
  color: var(--text-muted);
}

/* ---------- Mad-libs inline inputs ---------- */
.madlib-sentence {
  font-size: 1.2rem;
  color: var(--text);
  line-height: 2.2;
  flex-wrap: wrap;
  gap: 0.25rem 0.5rem;
}
.madlib-input,
.madlib-select {
  display: inline-block;
  border: none;
  border-bottom: 2px solid var(--accent);
  background: transparent;
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--accent);
  outline: none;
  padding: 0 0.25rem;
  min-width: 120px;
  border-radius: 0;
}
.madlib-select {
  cursor: pointer;
}
.madlib-input::placeholder {
  color: var(--text-muted);
  font-weight: 400;
}
/* These drop Bootstrap's outline via `outline: none`, so they need a
   focus indicator of their own or keyboard users lose the caret. */
.madlib-input:focus-visible,
.madlib-select:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: 3px;
}

.generate-btn {
  background: var(--border-strong);
  color: var(--text-muted);
  border-radius: 50px;
  padding: 0.8rem 2.2rem;
  font-size: 1rem;
  font-weight: 600;
  border: none;
  cursor: not-allowed;
}

/* ---------- Newsletter preview mockup ---------- */
.preview-card {
  background: var(--surface);
  border: 2px dashed var(--border-strong);
  border-radius: 20px;
  padding: 2rem 2.5rem;
}
.preview-card .preview-title {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 1.25rem;
}
.skeleton-line {
  height: 12px;
  background: linear-gradient(
    90deg,
    var(--border) 25%,
    var(--surface-hover) 50%,
    var(--border) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.6s infinite;
  border-radius: 6px;
  margin-bottom: 0.75rem;
}
@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .skeleton-line {
    animation: none;
  }
}
.skeleton-badge {
  display: inline-block;
  border: 2px dashed var(--border-strong);
  border-radius: 50px;
  padding: 0.35rem 1.2rem;
  font-size: 0.8rem;
  color: var(--text-muted);
  font-style: italic;
}
