/* Components this site has and the blog does not.
 *
 * Structure comes from fleet-ui/site.css and colour comes entirely from the
 * theme's twelve tokens, so there is not one hardcoded colour in this file.
 * That is what lets the same calculator render as Gray Wedding's elegant serif
 * and LAN Surf's terminal green without a per-site stylesheet.
 */

/* ── Tool index ───────────────────────────────────────────────────────
   .tool-grid and .tool-card USED to be defined here, and are now fleet-ui's.
   The parent blog draws the same card on its home page, and two definitions of
   one component is the fork that repo exists to prevent — see its README on
   why a component two consumers need is promoted rather than copied. What is
   left here is the one thing that is genuinely local: the grid is a <ul>. */

.tool-grid { list-style: none; padding: 0; margin: var(--space-5) 0 0; }

/* ── The form ───────────────────────────────────────────────────────── */

.tool-header {
  margin-bottom: 1.5rem;
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
}
.tool-header-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--r-1);
  background: var(--surface);
  color: var(--accent);
}
.tool-header .hero-title { margin: 0; }
.tool-header .hero-excerpt { margin: .35rem 0 0; }

.tool-inputs {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr));
}

.field { display: flex; flex-direction: column; gap: .35rem; }
.field-label { font-weight: 600; font-size: .95em; }
.field-unit { color: var(--muted); font-weight: 400; margin-left: .2rem; }
.field-help { margin: 0; color: var(--muted); font-size: .85em; line-height: 1.45; }
.input-check { width: 1.15rem; height: 1.15rem; }

.tool-actions { margin-top: 1.25rem; display: flex; gap: .75rem; align-items: center; }
.btn-quiet { color: var(--muted); text-decoration: underline; }

/* ── Results ────────────────────────────────────────────────────────── */

.tool-results { margin-top: 2rem; }

.headline-row {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  margin-bottom: 2rem;
}

.headline {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.25rem;
  background: var(--surface);
  display: flex;
  flex-direction: column;
  gap: .2rem;
}

.headline-value {
  font-family: var(--font-heading);
  font-size: var(--step-3, 1.9rem);
  line-height: 1.1;
  color: var(--accent);
  /* Tabular figures so a number changing as you type does not shift the
     layout under the cursor — the single most distracting thing a live
     calculator can do. */
  font-variant-numeric: tabular-nums;
}

.headline-label { font-weight: 600; }
.headline-help { color: var(--muted); font-size: .85em; line-height: 1.45; }

.result-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 1.75rem;
}

.result-table caption {
  text-align: left;
  font-weight: 600;
  padding-bottom: .5rem;
  font-family: var(--font-heading);
}

.result-table th,
.result-table td {
  text-align: left;
  padding: .55rem .5rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.result-table td {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.result-table th { font-weight: 500; }
.row-help { display: block; color: var(--muted); font-size: .85em; font-weight: 400; }

.unit-toggle {
  color: var(--muted);
  font-size: .85em;
  margin: 0 0 1rem;
}

.unit-toggle strong { color: var(--fg); }

/* ── Entity detail ──────────────────────────────────────────────────── */
/* An entity's fields are label/value pairs, not calculator outputs. Sharing
   `.result-table` right-aligned the value against the far edge of a
   full-width table, so "Batch size" and "5.28 gal" sat at opposite sides of
   the screen with a stretch of nothing between them. */

.spec-table {
  width: 100%;
  max-width: 42rem;
  border-collapse: collapse;
  margin-bottom: 1.75rem;
}

.spec-table caption {
  text-align: left;
  font-weight: 600;
  padding-bottom: .5rem;
  font-family: var(--font-heading);
}

.spec-table th,
.spec-table td {
  text-align: left;
  padding: .5rem .5rem .5rem 0;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.spec-table th {
  font-weight: 400;
  color: var(--muted);
  width: 40%;
}

.spec-table td { font-variant-numeric: tabular-nums; }

.spec-table tr:last-child th,
.spec-table tr:last-child td { border-bottom: none; }

@media (max-width: 34rem) {
  .spec-table th { width: 45%; }
}

/* ── Corpus lists ───────────────────────────────────────────────────── */
/* A search result is a LIST, not a readout. `.result-table` right-aligns its
   second column because a calculator's second column is a number; borrowing it
   here put a recipe's name and its beverage at opposite edges of the screen
   with a stretch of nothing between them. */

.corpus-count {
  font-weight: 600;
  font-family: var(--font-heading);
  padding-bottom: .5rem;
}

.corpus-list {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
}

/* A grid, not flex-with-a-gap. Flex puts the meta immediately after each
   name, so across a hundred rows the grey column zigzags along with however
   long each recipe happens to be called. A capped first column lines it up
   without sending it to the far edge of the screen, which is where the
   borrowed `.result-table` had it. */
.corpus-list li {
  display: grid;
  grid-template-columns: minmax(0, 21rem) 1fr;
  align-items: baseline;
  gap: .15rem 1rem;
  padding: .5rem .25rem;
  border-bottom: 1px solid var(--border);
}

.corpus-list li:last-child { border-bottom: none; }

.corpus-list a {
  font-weight: 500;
  text-decoration: none;
}

.corpus-list a:hover { text-decoration: underline; }

.corpus-meta {
  color: var(--muted);
  font-size: .85em;
}

/* Below the breakpoint there is no room for two columns, so the meta becomes
   a subtitle rather than being squeezed into nothing. */
@media (max-width: 34rem) {
  .corpus-list li { grid-template-columns: 1fr; }
}

/* ── Share ──────────────────────────────────────────────────────────── */

.tool-share {
  margin-top: 1rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  gap: .35rem;
}

.share-row { display: flex; gap: .5rem; align-items: center; }
.share-row .input { flex: 1; min-width: 0; }
.tool-share .input { font-size: .9em; }

/* ── The slider beside a bounded number ─────────────────────────────────
   Only rendered where the pack declared both ends of a range. It is a second
   way to drive the number field and carries no `name`, so the field stays the
   single source of the value and the URL cannot disagree with the form. */
.input-range { width: 100%; accent-color: var(--accent); }

/* ── What just changed ──────────────────────────────────────────────────
   The page has always recalculated as you type, and silently — which is
   indistinguishable from not at all, so a reader who types in one field and
   sees nothing move concludes the button is required. Only the values whose
   RENDERED TEXT changed get this, which is what makes it say which number
   moved rather than "something happened".

   Turned off entirely by fleet-ui's prefers-reduced-motion block, where it
   degrades to an instant update rather than to a stuck highlight. */
[data-output].is-changed {
  animation: value-changed 0.9s var(--ease, ease) 1;
}
@keyframes value-changed {
  0%   { color: var(--accent); }
  100% { color: inherit; }
}
.headline-value.is-changed { animation: headline-changed 0.9s var(--ease, ease) 1; }
@keyframes headline-changed {
  0%   { transform: translateY(-2px); opacity: .55; }
  100% { transform: none; opacity: 1; }
}

.tool-notes { margin-top: 2.5rem; }

@media (max-width: 32rem) {
  .result-table th, .result-table td { padding: .5rem .25rem; }
}

/* ── Take-aways ─────────────────────────────────────────────────────── */
/* artifacts.js scopes a print by putting `data-printing` on the subtree and
   `data-printing-scope` on the body. Hiding by `visibility` rather than
   `display` because the printing subtree has to keep its layout box — a
   display:none ancestor takes its children with it however visible they are. */

@media print {
  body[data-printing-scope] { visibility: hidden; }
  body[data-printing-scope] [data-printing] {
    visibility: visible;
    position: absolute;
    inset: 0;
    margin: 0;
  }
  body[data-printing-scope] [data-printing] * { visibility: visible; }
}

/* A label for the fermenter. Sized so the QR survives being printed small and
   stuck on a curved bucket: 4 cm is about the floor for a phone camera at
   arm's length, and the quiet border qr.js adds is what makes it scan against
   a dark surface at all. */
.fermenter-label {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .75rem;
  border: 1px solid var(--border);
  max-width: 20rem;
}

.fermenter-qr { width: 4cm; flex: 0 0 4cm; }
.fermenter-qr svg { width: 100%; height: auto; display: block; }

/* Twelve to a sheet, which is a standard 63.5 x 72 mm label stock and also
   roughly one batch of 500 ml bottles. */
.bottle-sheet {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .25rem;
}

.bottle-label {
  border: 1px dashed var(--border);
  padding: .75rem .5rem;
  min-height: 3.5cm;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
}

@media print {
  .bottle-sheet { gap: 0; }
  .bottle-label { border-style: solid; }
}

/* ── Verdicts and magnitudes ────────────────────────────────────────── */
/* A state is a WORD where a number was. `subnet` shipped
   `formula: 1 if usable >= needed else 0` with help text reading "1 means
   yes" — a verdict encoded as arithmetic and then explained in prose. The
   tone carries the same meaning the number was trying to. */

.tone-good { color: var(--good, #1a7f4b); }
.tone-warn { color: var(--warn, #9a6700); }
.tone-bad  { color: var(--bad, #b42318); }
.tone-neutral { color: inherit; }

/* Colour is never the only signal: the word itself says which state it is,
   so this reads the same to anyone who cannot tell the two apart. */
.headline-value.tone-good,
.headline-value.tone-warn,
.headline-value.tone-bad { font-weight: 600; }

/* A bar behind the figure, not instead of it. Someone comparing categories
   wants the shape; someone checking one wants the number. */
.bar-cell { position: relative; min-width: 8rem; }

.bar-track {
  display: block;
  height: .35rem;
  margin-bottom: .3rem;
  background: var(--border);
  border-radius: .2rem;
  overflow: hidden;
}

.bar-fill {
  display: block;
  height: 100%;
  background: var(--accent, currentColor);
  border-radius: .2rem;
  transition: width .2s ease;
}

@media (prefers-reduced-motion: reduce) {
  .bar-fill { transition: none; }
}

/* ── Levers and provenance ──────────────────────────────────────────── */
/* Nine fields all look equally important, so a reader changes none of them
   and takes a figure that two of the nine decided. The dots say which two,
   measured at the numbers in the form rather than asserted by the author. */

.lever {
  font-size: .7em;
  letter-spacing: .1em;
  vertical-align: middle;
  margin-left: .35em;
  color: var(--muted);
}

.lever-3 { color: var(--accent, currentColor); }

/* Where a number came from. `circuit_amps * volts * 0.8` and `panel_count * 21`
   looked exactly alike, and one is the NEC continuous-load rule while the
   other was a guess about somebody else's solar panel. */
.source {
  color: var(--muted);
  font-size: .8em;
  margin: .25rem 0 0;
  display: block;
}

.source-kind {
  text-transform: uppercase;
  letter-spacing: .06em;
  font-size: .85em;
  border: 1px solid var(--border);
  border-radius: .2rem;
  padding: 0 .3em;
}

.source-standard .source-kind,
.source-published .source-kind { color: var(--fg); }

/* ── Wedding printables ─────────────────────────────────────────────── */
/* An ESCORT card sits at the door and tells someone which table; a PLACE card
   sits on the table and marks their chair. They are constantly confused, so
   they are two buttons producing two different sheets rather than one. */

.card-sheet {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .25rem;
}

.card {
  border: 1px dashed var(--border);
  padding: 1rem .75rem;
  min-height: 4.5cm;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: .35rem;
}

.card strong { font-family: var(--font-heading); font-size: 1.15em; }

.seating-chart {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: 1rem;
}

.chart-table {
  border: 1px solid var(--border);
  padding: .75rem;
}

.chart-table ul { margin: .4rem 0 0; padding-left: 1.1rem; }
.chart-table li { font-size: .9em; }

@media print {
  .card-sheet { gap: 0; }
  .card { border-style: solid; break-inside: avoid; }
  .chart-table { break-inside: avoid; }
}

/* A control that sits inside a list row rather than in a form field. */
.input-inline {
  display: inline-block;
  width: auto;
  padding: .15rem .4rem;
  font-size: .85em;
  margin-right: .4rem;
}

/* ── Rack elevation ─────────────────────────────────────────────────── */
/* Drawn top down, the way you read a rack standing in front of it, and
   numbered bottom up, the way racks are actually numbered. */

.rack-elevation {
  border: 2px solid var(--fg);
  max-width: 26rem;
  font-family: var(--font-mono, ui-monospace, monospace);
}

.rack-u {
  display: grid;
  grid-template-columns: 3.5rem 1fr;
  gap: .5rem;
  align-items: center;
  min-height: 1.35rem;
  padding: 0 .4rem;
  border-bottom: 1px solid var(--border);
  font-size: .8rem;
}

.rack-u:last-child { border-bottom: none; }
.rack-u-filled { background: var(--surface, rgba(128, 128, 128, .12)); }
.rack-u-number { color: var(--muted); font-size: .85em; }

@media print {
  .rack-elevation { border-color: #000; }
  .rack-u-filled { background: #eee; }
  .rack-u { break-inside: avoid; }
}

/* ── Permit packet ──────────────────────────────────────────────────── */
/* Boxes rather than a schematic. Enough to show an inspector the topology and
   the conductor sizes, and honest about not being a stamped drawing. */

.permit-packet h2 {
  font-family: var(--font-heading);
  font-size: 1.05rem;
  margin: 1.25rem 0 .5rem;
}

.one-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
}

.one-line-box,
.one-line-run {
  border: 1px solid var(--fg);
  padding: .5rem .75rem;
  font-size: .8rem;
  white-space: pre-line;
  text-align: center;
  min-width: 7rem;
}

.one-line-run {
  border-style: dashed;
  border-width: 0 0 2px 0;
  border-radius: 0;
  padding: 0 .75rem .25rem;
  align-self: flex-end;
  color: var(--muted);
}

@media print {
  .permit-packet { break-inside: avoid; }
  .one-line-box, .one-line-run { border-color: #000; }
}

/* ── Dragging ───────────────────────────────────────────────────────── */
/* Pointer events, not the HTML5 drag API, so this works on a tablet — which
   is where somebody actually sits and moves people between tables. Every
   chip also carries a select, because nothing here is reachable by keyboard
   and nothing may be drag-only. */

.seating-plan {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: .75rem;
  margin-bottom: 1.5rem;
}

.seat-zone {
  border: 1px solid var(--border);
  border-radius: .3rem;
  padding: .6rem;
  min-height: 6rem;
  transition: background-color .12s ease, border-color .12s ease;
}

.seat-bench {
  border-style: dashed;
  grid-column: 1 / -1;
}

.seat-zone.drop-over {
  border-color: var(--accent, currentColor);
  background: var(--surface, rgba(128, 128, 128, .12));
}

.seat-chip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .4rem;
  padding: .3rem .45rem;
  margin-bottom: .3rem;
  border: 1px solid var(--border);
  border-radius: .25rem;
  background: var(--bg);
  /* The browser must not claim the gesture for scrolling before pointermove
     sees it. Without this a drag that starts on a chip scrolls the page on
     every touch device. */
  touch-action: none;
  cursor: grab;
}

.seat-chip.dragging {
  cursor: grabbing;
  opacity: .85;
  /* Lifted out of the flow so it tracks the finger over other zones rather
     than being clipped by the one it started in. */
  position: relative;
  z-index: 10;
  pointer-events: none;
}

/* While something is in the air, stop the drag turning into a text selection
   the moment it passes over a label. */
body.is-dragging { user-select: none; -webkit-user-select: none; }

@media (prefers-reduced-motion: reduce) {
  .seat-zone { transition: none; }
}

/* A chip is a pointer affordance. With no pointer there is no drag, so the
   grab cursor would be a lie — the select inside it is the whole interface. */
@media (hover: none) and (pointer: coarse) {
  .seat-chip { cursor: default; }
}

/* ── Panes ──────────────────────────────────────────────────────────── */
/* Five identically-headed sections give a reader no sense of where to start
   or how far through they are. A number and a live status line turn the
   headings into a summary of the design instead of a list of section names. */

.pane-title {
  display: flex;
  align-items: baseline;
  gap: .55rem;
  flex-wrap: wrap;
}

.pane-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--border);
  font-family: var(--font-body, inherit);
  font-size: .75rem;
  font-weight: 600;
  color: var(--muted);
}

.pane-status {
  font-family: var(--font-body, inherit);
  font-size: .8rem;
  font-weight: 400;
  color: var(--muted);
  margin-left: auto;
}

/* The answer, above the form that produces it. Every calculator on this site
   puts its headline at the top; the apps were burying theirs under a screen
   of inputs, so on a phone you typed and then scrolled to find out what
   happened. */
.pane-answer {
  font-family: var(--font-heading);
  font-size: 1.05rem;
  margin: 0 0 .75rem;
}

/* A form that collapses once it has done its job. Native <details>: works
   with no JavaScript, keyboard reachable, and announced correctly without any
   aria bookkeeping. Open when there is nothing yet, shut once there is. */
.pane-form {
  border: 1px solid var(--border);
  border-radius: .3rem;
  padding: .5rem .7rem;
  margin-bottom: .9rem;
}

.pane-form > summary {
  cursor: pointer;
  font-weight: 500;
  padding: .15rem 0;
}

.pane-form[open] > summary {
  margin-bottom: .6rem;
  border-bottom: 1px solid var(--border);
  padding-bottom: .45rem;
}

.pane-form > summary::marker { color: var(--muted); }

/* ── Roof canvas ────────────────────────────────────────────────────── */
/* The plane drawn to its own proportions, with the setback inset by the same
   fraction of each side that it is in feet. Everything is a percentage, so
   the drawing stays true at any width — the drawing IS the data.

   Cells are buttons: keyboard reaches them, a screen reader announces them as
   switches, and nothing here is pointer-only. */

.roof-plane {
  border: 1px solid var(--border);
  border-radius: .3rem;
  padding: .7rem;
  margin-bottom: 1rem;
}

.roof-plan {
  position: relative;
  width: 100%;
  max-width: 34rem;
  background: var(--surface, rgba(128, 128, 128, .1));
  border: 2px solid var(--fg);
  margin: .5rem 0;
  /* A wide, shallow plane would otherwise be a few pixels tall. */
  min-height: 4rem;
}

.roof-setback {
  position: absolute;
  border: 1px dashed var(--muted);
  pointer-events: none;
}

.roof-cells {
  position: absolute;
  display: grid;
  gap: 2px;
  padding: 2px;
}

.roof-cell {
  border: 1px solid var(--border);
  background: transparent;
  border-radius: 1px;
  padding: 0;
  min-width: 0;
  min-height: 0;
  cursor: pointer;
  /* The browser must not claim a sweep for scrolling before pointerenter
     sees it. */
  touch-action: none;
}

.roof-cell-on {
  background: var(--accent, currentColor);
  border-color: var(--accent, currentColor);
}

.roof-cell:focus-visible {
  outline: 2px solid var(--fg);
  outline-offset: 1px;
  z-index: 1;
}

.roof-empty {
  grid-column: 1 / -1;
  align-self: center;
  text-align: center;
  color: var(--muted);
  font-size: .8rem;
  margin: 0;
}

@media print {
  .roof-plan { border-color: #000; }
  .roof-cell-on { background: #333; border-color: #333; }
  .roof-plane .tool-actions { display: none; }
}
