:root {
  --purple: #6a2265;
  --yellow: #ffc629;
  --pale: #faf5f9;
  --ink: #201f1c;
  --border: #d9c3d3;
  --muted: #8a6b85;
  --warn-bg: #fff3d2;
  --warn-ink: #7a5b0a;

  /* One type scale for every text field/list/label in the app — three sizes, not the
     dozen near-identical ones (10.5/11/12/12.5/13px) that had crept in field by field.
     --fs-eyebrow: uppercase mono micro-labels; --fs-body: every control and list text;
     --fs-hero: the one number meant to dominate the page (the total). */
  --fs-eyebrow: 12px;
  --fs-body: 12px;
  --fs-hero: 28px;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
  /* The app fills the viewport and never scrolls at the page level (§ layout brief) —
     only specific inner lists (.list-scroll, .recap-list) scroll their own content. */
  overflow: hidden;
}

body {
  display: flex;
  flex-direction: column;
  font-family: "IBM Plex Sans", sans-serif;
  color: var(--ink);
  background: var(--pale);
}

.topbar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 20px 32px 8px;
}

.logo-mark {
  height: 40px;
  width: auto;
  display: block;
}

.logo-wordmark {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}

.logo-brand {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--purple);
}

.logo-tagline {
  font-family: "IBM Plex Sans", sans-serif;
  font-size: 11px;
  font-style: italic;
  color: var(--purple);
}

/* Positioning only — the button itself reuses .btn-round, the UI's standard button, so a
   change to that style carries here too. */
.topbar-action {
  margin-left: 24px;
}

.topbar-version {
  margin-left: auto;
  font-family: "IBM Plex Mono", monospace;
  font-size: 11px;
  color: var(--muted);
}

#app {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 8px 24px 24px;
}

.columns {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: stretch;
  gap: 20px;
}

.col {
  padding: 24px;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 1px 3px rgba(32, 31, 28, 0.06);
}

.col-left {
  width: 400px;
  flex-shrink: 0;
  /* The column itself never scrolls — only .list-scroll blocks inside it do (composition,
     options, a-la-carte). Everything else here is a fixed number of controls, sized to
     fit without needing a column-level scrollbar. */
  overflow: hidden;
}

.col-left form {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
}

.col-center {
  flex: 1;
  min-width: 340px;
  /* Hidden on a tall enough viewport, where .card-elevation/.card-bom's flex sizing and
     min-heights already fit without clipping anything. The
     @media (max-height: ...) rule near the bottom of this file switches this column to
     scrolling its own content on short viewports instead, rather than letting flexbox
     squeeze .card-bom below a usable size (the page itself still never scrolls). */
  overflow: hidden;
  background: transparent;
  box-shadow: none;
  padding: 0;
  gap: 16px;
}

/* One rectangle per section of the middle column (infos chantier, elevation, nomenclature)
   instead of one big card — .col-center itself is a plain flex column, transparent, and
   each direct section below gets its own white card. */
.card {
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 1px 3px rgba(32, 31, 28, 0.06);
  padding: 20px;
}

/* .card-summary sizes itself to its content (a single-line strip of values) and never
   grows or shrinks past that. .card-elevation and .card-bom are the only two cards left
   with a positive flex-grow in this column, so they still split the remaining height in a
   3:2 ratio (the drawing is what the client looks at, the nomenclature is what they order
   from) via their own `flex-basis: 0`. Each card's own floor below still wins over the
   ratio on a short viewport. */
.card-summary {
  flex-shrink: 0;
  padding: 12px 20px;
}

.card-elevation {
  flex: 8 1 0;
  min-height: 200px;
  display: flex;
  flex-direction: column;
  /* Anchors .calc-notes-button/.calc-notes-panel to this card's corner (see the bottom of
     this file). */
  position: relative;
}

.card-bom {
  flex: 3 1 0;
  /* Floor tall enough for the sticky header plus ~3 data rows, so the table body is never
     squeezed to invisibility when the column is short (see .col-center below). */
  min-height: 160px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.col-right {
  width: 400px;
  flex-shrink: 0;
  overflow: hidden;
  /* Two independent white cards (see .card) rather than one, matching how .col-center
     already hosts several — the price recap and the project/PDF block are unrelated
     pieces of information and read better as separate rectangles. */
  background: transparent;
  box-shadow: none;
  padding: 0;
  gap: 16px;
}

/* Same 3:2-style split as .card-elevation/.card-bom: the price recap is what the client
   reads most, the project name/PDF block is a one-off action, so they share the column's
   height 3:1 rather than evenly. Each floor below still wins over the ratio on a short
   viewport. */
.card-recap {
  flex: 5 1 0;
  min-height: 220px;
  display: flex;
  flex-direction: column;
}

.card-project {
  flex: 1 1 0;
  min-height: 110px;
  display: flex;
  flex-direction: column;
}

.field-group {
  margin-bottom: 22px;
}

/* The last section (compléments de commande) grows to absorb whatever vertical room the fixed-size
   sections above it don't use, and its own list scrolls within that — instead of risking
   getting clipped below the fold of a column that (by design) never scrolls itself. */
.field-group:last-child {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  margin-bottom: 0;
}

.field-group:last-child .list-scroll {
  flex: 1;
  min-height: 40px;
  max-height: none;
}

.field-label {
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.08em;
  color: var(--purple);
  text-transform: uppercase;
  font-weight: 600;
  margin-bottom: 9px;
}

.field {
  margin-bottom: 8px;
}

/* Three related selects side by side (famille/pose/couleur poteau) instead of stacked —
   saves enough vertical room in a fixed-height, non-scrolling column (see .col-left) that
   the à-la-carte block stays visible without scrolling past it. */
.field-row {
  display: flex;
  gap: 8px;
}

.field-row .field {
  flex: 1;
  min-width: 0;
}

/* Composition block: matière/couleur/lame/nombre de lames laid out as a fixed 2x2 grid
   instead of stacked, so the two short selects and the number field don't waste a full
   row each. */
.field-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.field-grid .field {
  margin-bottom: 0;
}

.field label {
  display: block;
  font-size: var(--fs-eyebrow);
  color: var(--muted);
  margin-bottom: 4px;
}

select,
input[type="text"],
input[type="number"] {
  width: 100%;
  padding: 9px 8px;
  border: 1px solid var(--border);
  background: #fff;
  font-size: var(--fs-body);
  font-family: "IBM Plex Sans", sans-serif;
  border-radius: 4px;
}

select:focus,
input:focus {
  outline: 2px solid var(--purple);
  outline-offset: 2px;
}

.field-inline {
  display: flex;
  align-items: center;
  gap: 8px;
}

.add-row {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}

.add-row select {
  flex: 1;
}

.btn-round {
  flex-shrink: 0;
  border: 2px solid var(--purple);
  color: var(--purple);
  background: #fff;
  font-size: var(--fs-body);
  font-weight: 600;
  cursor: pointer;
  border-radius: 4px;
  padding: 10px;
  min-height: 38px;
}

.btn-round:hover {
  background: var(--pale);
}

/* An <a> doesn't get a button's box model or text styling for free: without this it stays
   inline (ignoring the padding above), keeps its underline, and left-aligns multi-word
   labels. Complements .btn-round rather than duplicating it. Flex-centers the icon+label
   pair, spans the full width of its card, and sticks to the card's bottom via
   margin-top: auto in its flex-column parent (.recap-report). */
a.btn-round,
a.btn-round:hover,
a.btn-round:focus,
a.btn-round:visited,
a.btn-round:active {
  text-decoration: none;
}

a.btn-round {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin-top: auto;
}

.list-scroll {
  max-height: 180px;
  overflow-y: auto;
  margin-bottom: 8px;
}

.list-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-body);
  padding: 4px 0;
}

.btn-remove {
  border: none;
  background: none;
  color: #9c2b20;
  cursor: pointer;
  font-size: var(--fs-body);
}

.hint {
  font-size: var(--fs-body);
  color: var(--muted);
}

.banner {
  padding: 10px 14px;
  font-size: var(--fs-body);
  font-weight: 500;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  border-radius: 6px;
  margin-bottom: 12px;
}

.banner.blocking {
  background: var(--ink);
  color: #fff;
}

.banner.warning {
  background: var(--warn-bg);
  color: var(--warn-ink);
}

/* "Infos chantier" — a compact, read-only summary of what the client has ended up with.
   Items spread across the card's full width (space-between) instead of packing to the
   left, while rows stay tight (small row-gap) so the card stays as short as its content
   allows (see .card-summary's own reduced vertical padding) instead of stretching into
   airy, sparse rows. */
.site-summary {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 2px 18px;
}

.site-summary-item {
  display: flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
  line-height: 1.3;
}

.site-summary-label {
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--purple);
  font-weight: 600;
}

.site-summary-value {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
}

/* Fills whatever height .card-elevation ends up with (its flex-basis/min-height above),
   instead of a fixed 440px — .elevation-stage below then scales the drawing to that height
   while keeping the SVG's aspect ratio. */
.elevation-stage-wrap {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Scales with the wrap's height, capped at the SVG's native 640x520 size so it never
   grows past 1:1 on a tall column — width is derived from height via aspect-ratio, so the
   drawing never distorts. */
.elevation-stage {
  position: relative;
  height: 100%;
  width: auto;
  max-width: 100%;
  max-height: 520px;
  aspect-ratio: 640 / 520;
}

.elevation-stage svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* Fills its card (.card-bom) and scrolls its own content when the BOM has many lines —
   never the page (see html/body overflow:hidden above). */
.bom-section {
  flex: 1;
  min-height: 110px;
  overflow-y: auto;
}

.bom-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-body);
}

.bom-table th,
.bom-table td {
  text-align: left;
  padding: 6px 10px 6px 0;
  border-bottom: 1px solid #e4cfe0;
  white-space: nowrap;
}

/* Every column but the first two holds a quantity: centered, header and value alike, so a
   figure reads directly under its own label instead of drifting to the left of it. Code
   and designation stay left-aligned — they are text of varying length. */
.bom-table th:nth-child(n + 3),
.bom-table td:nth-child(n + 3) {
  text-align: center;
  padding-left: 10px;
}

.bom-subdetail {
  color: var(--muted);
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--fs-eyebrow);
  white-space: normal;
  margin-top: 2px;
}

.bom-table th {
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 600;
  /* Keeps the header row in view while `.bom-section` scrolls its body — the header's own
     background must be opaque or scrolled rows would show through underneath it. */
  position: sticky;
  top: 0;
  background: #fff;
  z-index: 1;
}

.recap-title {
  flex-shrink: 0;
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.08em;
  color: var(--muted);
  text-transform: uppercase;
  font-weight: 600;
  margin-bottom: 14px;
}

/* Grows to fill whatever space the nomenclature doesn't need, so .recap-total below
   always sits at the bottom of the column — never floating right after a short list. */
.recap-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.recap-line {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: var(--fs-body);
  padding-bottom: 6px;
  margin-bottom: 6px;
  border-bottom: 1px solid #e4cfe0;
}

.recap-line-meta {
  color: var(--muted);
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--fs-eyebrow);
  white-space: nowrap;
  margin-top: 2px;
}

.bom-note {
  color: var(--muted);
  font-style: italic;
  font-size: var(--fs-eyebrow);
  margin-top: 2px;
  white-space: normal;
}

.discount-field {
  flex-shrink: 0;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-top: 8px;
}

.discount-field label {
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-weight: 600;
}

.discount-field input {
  width: 72px;
  text-align: right;
}

.recap-total {
  flex-shrink: 0;
  border-top: 2px solid var(--purple);
  padding-top: 12px;
  margin-top: 8px;
}

.recap-total .label {
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/* Content of .card-project: the project name field, then the PDF button pinned to the
   card's bottom (margin-top: auto below) regardless of how short the field above is. */
.recap-report {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.recap-total .value {
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--fs-hero);
  font-weight: 700;
  color: var(--purple);
}

.value-discounted {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.value-struck {
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--muted);
  text-decoration: line-through;
}

/* Info button + panel explaining the page's formulas (checkbox-driven, no JS needed —
   CLAUDE.md §3 stack: vanilla only for fine-grained interactivity, and this doesn't need
   even that much). */
.calc-notes-toggle {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.calc-notes-button {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 20;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--purple);
  color: var(--purple);
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: "IBM Plex Mono", monospace;
  font-size: var(--fs-body);
  font-weight: 700;
  font-style: italic;
  cursor: pointer;
  user-select: none;
}

.calc-notes-panel {
  display: none;
  position: absolute;
  top: 38px;
  right: 10px;
  z-index: 30;
  width: min(420px, calc(100vw - 40px));
  max-height: min(70vh, 520px);
  overflow-y: auto;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(32, 31, 28, 0.18);
  padding: 12px 14px;
}

.calc-notes-toggle:checked ~ .calc-notes-panel {
  display: block;
}

.calc-notes-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-weight: 600;
  margin-bottom: 8px;
}

.calc-notes-close {
  cursor: pointer;
  color: var(--muted);
}

.calc-notes-list {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.calc-notes-item dt {
  font-weight: 600;
  font-size: var(--fs-body);
}

.calc-notes-value {
  font-family: "IBM Plex Mono", monospace;
  color: var(--purple);
}

.calc-notes-item dd {
  margin: 2px 0 0;
  font-size: var(--fs-eyebrow);
  color: var(--muted);
  line-height: 1.4;
}

/* A wide-but-short viewport (e.g. 1366x768 with browser chrome) doesn't hit the
   max-width breakpoint below, yet the topbar + "infos chantier" card + .card-elevation's
   and .card-bom's min-heights (200px / 160px, see above) can add up to more than the
   window's height. Past this point, flexbox has nowhere left to shrink .card-elevation or
   .card-bom without going under their floors — so .col-center scrolls its own content
   instead of letting the nomenclature card get squeezed out of view. The page itself
   still never scrolls (html/body overflow:hidden above still holds). */
@media (max-height: 760px) {
  .col-center {
    overflow-y: auto;
  }
}

/* Below the combined minimum width of the three fixed-width columns (400 + 340 + 400px),
   there is no room to keep them side by side (see .columns/.col-left/.col-center/.col-right
   above) — stack them instead and let the page scroll to reach the drawing and the quote. */
@media (max-width: 900px) {
  html,
  body {
    height: auto;
    overflow: auto;
  }

  /* Desktop pins #app/.columns/.col-center to the viewport height via flex:1 +
     min-height:0 (see rules above) so everything fits one screen with no page scroll.
     Stacking the columns needs the opposite: every level of that chain must size to its
     content instead, or the still-height-constrained flex items get squeezed and their
     overflow:visible content spills into the column below (e.g. the SVG bleeding onto
     the price) instead of the page simply growing and scrolling. */
  #app {
    flex: none;
    min-height: 0;
    height: auto;
    padding: 8px 24px 24px;
  }

  .columns {
    flex: none;
    flex-direction: column;
    min-height: 0;
    height: auto;
  }

  .col {
    flex: none;
    min-height: 0;
    height: auto;
    overflow: visible;
  }

  .col-left,
  .col-center,
  .col-right {
    width: 100%;
    min-width: 0;
  }

  .col-left form {
    height: auto;
  }

  .field-group:last-child {
    flex: none;
  }

  .field-group:last-child .list-scroll {
    flex: none;
    min-height: 0;
    max-height: 180px;
  }

  .card-bom {
    flex: none;
    height: auto;
    overflow: visible;
  }

  /* Missing from this reset, .card-elevation keeps its desktop flex:8 1 0 with no
     overflow set — .col-center's now-auto height gives it no free space to grow into,
     so it stays pinned near its 200px floor while .elevation-stage-wrap/.elevation-stage
     below still scale up to their full (up to 640x520) size, spilling that overflow
     upward over .card-summary instead of pushing the card's own box down with it. */
  .card-elevation {
    flex: none;
    height: auto;
    overflow: visible;
  }

  .elevation-stage-wrap {
    height: auto;
    width: 100%;
  }

  .elevation-stage {
    width: 100%;
    max-width: 640px;
    height: auto;
    aspect-ratio: 640 / 520;
  }

  .elevation-stage svg {
    width: 100%;
    height: 100%;
  }

  .bom-section {
    flex: none;
    max-height: 280px;
  }

  .col-right {
    height: auto;
  }

  .card-recap,
  .card-project {
    flex: none;
    min-height: 0;
  }

  .recap-list {
    flex: none;
    max-height: 280px;
  }
}
