/* Still Log page layout. ui/ui.min.css supplies the components (buttons, fields, cards, tables,
   badges, alerts) in Flowbite's look and the colour tokens (--bg, --surface, --text, --link...) used here. */
/* Chart series */
:root { --sg: #1a56db; --temp: #e02424; --s1: #1a56db; --s2: #7e3af2; --s3: #047481; --s4: #d61f69; --ph: #9061f9; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --sg: #76a9fa; --temp: #f98080; --s1: #76a9fa; --s2: #ac94fa; --s3: #16bdca; --s4: #f17eb8; --ph: #cabffd; }
}
:root[data-theme="dark"] { --sg: #76a9fa; --temp: #f98080; --s1: #76a9fa; --s2: #ac94fa; --s3: #16bdca; --s4: #f17eb8; --ph: #cabffd; }

body { font-variant-numeric: tabular-nums; }
strong, b { font-weight: 600; }
a { color: var(--link); text-decoration: none; }
a:hover { color: var(--link-hover); text-decoration: underline; }
a:focus-visible, summary:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: .25rem; }
h1 { margin: .25rem 0 .25rem; line-height: 1.3; }
h2 { margin: 2.25rem 0 1rem; }
h3 { margin: 1rem 0 .5rem; }
p { margin: 0 0 .75rem; }
main ul { list-style: square; padding-left: 1.25rem; margin: 0 0 1rem; }
main ol { list-style: decimal; padding-left: 1.25rem; }
main li { overflow-wrap: anywhere; margin: .25rem 0; }
main ul ul { padding-left: 1.1rem; }

/* Top bar: brand, sections and search on one line. When the sections don't all fit they scroll
   sideways; on a phone they fold behind the menu button instead (see Phones below). */
.top { position: sticky; top: 0; z-index: 10; display: flex; align-items: center; gap: 1rem; padding: .625rem 1rem; }
.top nav { flex: 1; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.top nav::-webkit-scrollbar { display: none; }
.top nav ul { display: flex; gap: .125rem; list-style: none; margin: 0; padding: 0; }
@media (min-width: 75rem) { .top { padding: .625rem max(1rem, calc((100vw - var(--page-w)) / 2)); } }

/* Page width: 1200 px on a laptop, wider on big monitors so a 1440p 16:9 or 21:9 screen isn't mostly margin.
   Paragraphs keep a readable line length however wide the page gets; tables and cards use the room. */
:root { --page-w: 1200px; }
@media (min-width: 110rem) { :root { --page-w: 1600px; } }
@media (min-width: 150rem) { :root { --page-w: 2000px; } html { font-size: 106.25%; } }
@media (min-width: 200rem) { :root { --page-w: 2400px; } }
main { max-width: var(--page-w); margin: 0 auto; padding: 2rem 1rem 4rem; }
main p, main .hint { max-width: 90ch; }
/* Graphs beside the page. Only an ultrawide screen (21:9 1440p is 3440 px) has room: there the page splits into
   the usual content and a sticky column of the page's graphs, and the copies in the page itself are hidden. */
.side { display: none; }
@media (min-width: 200rem) {
  .page.has-side { display: grid; grid-template-columns: minmax(0, 1fr) 46rem; gap: 2rem; max-width: var(--page-w); margin: 0 auto; }
  .page.has-side main { max-width: none; margin: 0; }
  .page.has-side .side { display: block; position: sticky; top: 4.5rem; align-self: start; max-height: calc(100vh - 5rem); overflow-y: auto;
    padding: 2rem 1rem 2rem 0; }
  .page.has-side .side h2:first-child { margin-top: 0; }
  .page.has-side main .inline-chart { display: none; }
}
.muted, .hint { color: var(--text-2); }
.hint { font-size: .75rem; line-height: 1.33; margin: .25rem 0; }
.card { margin: 0 0 1rem; }
.grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); margin-top: 1rem; }
.grid > .card { margin: 0; }
.grid > .card h3 { margin-top: 0; }

/* Figures read as a row of small cards: label above, value below. */
.stats { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); margin: 1.5rem 0 1rem; }
.stat { display: flex; flex-direction: column-reverse; justify-content: flex-end; padding: 1rem 1.25rem; background: var(--surface);
  border: 1px solid var(--border); border-radius: .5rem; box-shadow: 0 1px 2px 0 rgb(0 0 0 / .05); }
.stat b { display: block; font-size: 1.25rem; font-weight: 600; line-height: 1.4; margin-top: .25rem; color: var(--text); }
.stat span { color: var(--text-2); font-size: .8125rem; }

/* Back link above a detail page's title, e.g. a plan back to the Plans list. Big enough to tap on a phone. */
.crumb { display: inline-flex; align-items: center; min-height: 2.75rem; font-size: .875rem; font-weight: 500; }
.crumb + .head h1, .crumb + h1 { margin-top: 0; }

.head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-end; gap: 1rem; }
.head h1 .badge { margin-left: .25rem; }
.head + .scroll { margin-top: .75rem; }
.actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.actions form.inline { margin: 0; gap: .5rem; }
.scroll { overflow-x: auto; margin-bottom: 1rem; }
/* A table on the page sits in a rounded, bordered box; inside a card it doesn't need one. */
.scroll:has(> table) { border: 1px solid var(--border); border-radius: .5rem; box-shadow: 0 1px 2px 0 rgb(0 0 0 / .05); }
.tile .scroll:has(> table) { box-shadow: none; }

/* Tables: a total row and right-aligned figures. */
.table td.n, .table th.n { text-align: right; white-space: nowrap; }
.table td.nowrap { white-space: nowrap; }
.table td { vertical-align: top; }
.table th { white-space: nowrap; }

/* Forms: the label wraps its field. */
form { margin: 0; }
form.stack { display: grid; gap: 1.5rem; max-width: 720px; align-content: start; }
form.stack .cols { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
form.inline { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-end; margin: 1rem 0; }
label { display: flex; flex-direction: column; gap: .5rem; font-size: .875rem; font-weight: 500; color: var(--text); }
/* Side-by-side fields line up even when one label wraps to two lines: each label in a .cols row is as tall as
   the row, and its name sits at the bottom, just above the field. A hint after a field is shown above it, with
   the name, so the fields stay in line with their neighbours'. */
.cols > label:not(.check):not(.chip) { justify-content: flex-end; }
.cols > label:not(.check):not(.chip) > :is(input, select, textarea, .input, .select) { order: 1; }
label.check { flex-direction: row; align-items: center; gap: .75rem; font-weight: 500; color: var(--text); cursor: pointer; }
/* Every tick box is drawn as a Flowbite toggle switch: grey track when off,
   blue with the knob slid right when on. Table row pickers use the small size. */
input[type=checkbox] { -webkit-appearance: none; appearance: none; position: relative; flex: none; box-sizing: border-box;
  width: 2.75rem; height: 1.5rem; margin: 0; padding: 0; border: 0; border-radius: 9999px; cursor: pointer; color: transparent;
  background: #e5e7eb; background-image: none; transition: background-color .15s ease; }
input[type=checkbox]::before { content: ""; position: absolute; top: 2px; left: 2px; width: 1.25rem; height: 1.25rem;
  border-radius: 50%; background: #fff; border: 1px solid #d1d5db; box-sizing: border-box; transition: transform .15s ease; }
input[type=checkbox]:checked, input[type=checkbox]:checked:hover, input[type=checkbox]:checked:focus { background: #1c64f2; background-image: none; }
input[type=checkbox]:checked::before { transform: translateX(1.25rem); border-color: #fff; }
input[type=checkbox]:focus { box-shadow: none; outline: none; }
input[type=checkbox]:focus-visible { box-shadow: 0 0 0 4px #c3ddfd; }
input[type=checkbox]:disabled { cursor: not-allowed; opacity: .5; }
:root[data-theme="dark"] input[type=checkbox]:not(:checked) { background: #374151; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) input[type=checkbox]:not(:checked) { background: #374151; } }
td > input[type=checkbox] { width: 2.25rem; height: 1.25rem; vertical-align: middle; }
td > input[type=checkbox]::before { width: 1rem; height: 1rem; }
td > input[type=checkbox]:checked::before { transform: translateX(1rem); }
.task-days td, .task-days thead th:not(:first-child) { text-align: center; }
.scroll:has(> .task-days) { max-width: 44rem; }
.task-days tbody th { font-weight: 500; white-space: nowrap; }
.task-days thead th { white-space: normal; vertical-align: bottom; }
.task-days .narrow-only { display: none; }
@media (max-width: 40rem) { .task-days .wide-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .task-days .narrow-only { display: inline; } }
/* A row of toggles (still days, parts) needs more room than a row of buttons. */
.actions:has(> label.check) { gap: .75rem 1.5rem; }
@media (prefers-reduced-motion: reduce) { input[type=checkbox], input[type=checkbox]::before { transition: none; } }
.input[type=number] { width: 8rem; }
form.stack .input[type=number] { width: 100%; }
.textarea { min-height: 5rem; }
input[type=file] { font: inherit; color: var(--text); }
/* Flowbite pulls the file button 1rem left (it expects padding on the input), which cut off its left side. */
input[type=file]::file-selector-button { font: inherit; font-weight: 500; margin: 0 .75rem 0 0; margin-inline: 0 .75rem; padding: .5rem 1rem; border: 0; border-radius: .5rem;
  background: #1f2937; color: #fff; cursor: pointer; }

.draws .row { display: flex; flex-wrap: wrap; gap: 1rem; margin-bottom: .5rem; }
.draws select { max-width: 32rem; }

pre.method { white-space: pre-wrap; font: inherit; margin: 0; background: none; padding: 0; }
dl.kv { display: grid; grid-template-columns: max-content 1fr; gap: .5rem 1.5rem; margin: 0; }
dl.kv dt { color: var(--text-2); } dl.kv dd { margin: 0; }

.trace, .trace ul { list-style: none; padding-left: 1.25rem; margin: 0; }
.trace { padding-left: 0; }
.trace li { position: relative; margin: .5rem 0; }
.trace ul { border-left: 1px solid var(--border); margin-left: .5rem; }
.trace .node { padding: .5rem 1rem; background: var(--surface); border: 1px solid var(--border); border-left: 3px solid var(--link); border-radius: .5rem; }
.trace .src { font-size: .75rem; color: var(--text-2); }
.trace ul.lots { border: 0; margin: .25rem 0; padding-left: 1rem; list-style: square; }
.trace ul.lots li { margin: 0; }
.trace a { overflow-wrap: anywhere; }
table .lot { white-space: nowrap; }
details > summary { cursor: pointer; color: var(--link); margin: .5rem 0; }

.chart { width: 100%; height: auto; display: block; background: var(--surface); padding: .5rem 0; border: 1px solid var(--border); border-radius: .5rem; }
.chart .grid { stroke: var(--border); stroke-width: 1; }
.chart .lbl { fill: var(--text-2); font-size: 11px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.chart .lbl.sg { fill: var(--sg); } .chart .lbl.temp { fill: var(--temp); }
.chart .line { fill: none; stroke-width: 2; }
.chart .line.sg { stroke: var(--sg); } .chart .line.temp { stroke: var(--temp); stroke-dasharray: 5 4; }
.chart .dot.sg { fill: var(--sg); }
.chart .line.manual { stroke-opacity: .45; }
.chart .line.s1 { stroke: var(--s1); } .chart .dot.s1 { fill: var(--s1); } .legend b.s1 { color: var(--s1); }
.chart .line.s2 { stroke: var(--s2); } .chart .dot.s2 { fill: var(--s2); } .legend b.s2 { color: var(--s2); }
.chart .line.s3 { stroke: var(--s3); } .chart .dot.s3 { fill: var(--s3); } .legend b.s3 { color: var(--s3); }
.chart .line.s4 { stroke: var(--s4); } .chart .dot.s4 { fill: var(--s4); } .legend b.s4 { color: var(--s4); }
.chart.ph { margin-top: .5rem; }
.chart .band { fill: var(--success); fill-opacity: .12; }
.chart .line.ph { stroke: var(--ph); stroke-width: 1.5; } .chart .dot.ph { fill: var(--ph); }
.chart .dot.ph.out { fill: var(--error); } .chart .lbl.ph, .legend b.ph { fill: var(--ph); color: var(--ph); }
.chart .target { stroke: var(--text-2); stroke-dasharray: 2 4; }
.legend { font-size: .75rem; color: var(--text-2); margin: .5rem 0 1rem; }
.legend b { font-weight: 600; } .legend b.sg { color: var(--sg); } .legend b.temp { color: var(--temp); }
.ok { color: var(--success); } .out { color: var(--error); font-weight: 600; }

.cut-summary { display: none; gap: .3rem 1rem; flex-wrap: wrap; }
@media (max-width: 40rem) {
  main { padding-top: 1.5rem; }
  h1 { font-size: 1.75rem; }
  .input[type=number] { width: 6.5rem; }
  .stats { gap: .5rem; } .stat { padding: .625rem .875rem; } .stat b { font-size: 1.125rem; }
  .tile { padding: 1rem; }
  /* Jars as stacked rows so ABV and LAA are visible without sideways scrolling. */
  table.jars thead, table.jars tfoot { display: none; }
  .table.jars tbody tr { display: grid; grid-template-columns: repeat(4, 1fr); gap: .25rem .75rem;
    padding: .5rem 0; block-size: auto; border-bottom: 1px solid var(--border); }
  table.jars td[data-label="Cut"] { grid-column: span 3; }
  table.jars td.pick { order: 99; }
  table.jars td.pick:empty { display: none; }
  .table.jars td { border: 0; padding: .1rem .25rem; text-align: left; height: auto; }
  table.jars td[data-label]::before { content: attr(data-label); display: block; font-size: .75rem; color: var(--text-2); }
  .cut-summary { display: flex; }
}
@media print {
  .top, .no-print, form { display: none !important; }
  body { background: #fff; color: #000; }
  .tile, .stat, .table td, .table tbody tr { background: #fff !important; color: #000 !important; }
}
body.print .top, body.print .no-print { display: none; }
code.url { overflow-wrap: anywhere; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .8125rem; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; background: var(--surface); padding: 1rem; border-radius: .5rem; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .75rem; }
.photos { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); margin: .5rem 0 1rem; }
.photos figure { margin: 0; background: var(--surface); border: 1px solid var(--border); border-radius: .5rem; overflow: hidden; }
.photos img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: var(--surface-2); }
.photos figcaption { padding: .5rem 1rem 1rem; font-size: .75rem; display: grid; gap: .25rem; overflow-wrap: anywhere; }
.photos details > summary { margin: 0; }
.photos form.inline { margin: .5rem 0; }
.photos form.inline input { width: 100%; }
@media print { .photos { grid-template-columns: repeat(4, 1fr); } .photos figure { break-inside: avoid; } }
.actions form.inline { flex-wrap: nowrap; }
.actions .select { inline-size: auto; min-width: 9rem; }

/* Inventory: making from a recipe uses full-width tables, and a stocktake is one number per row. */
form.make { display: grid; gap: 1.5rem; }
form.make > h2 { margin: 1rem 0 0; }
form.make .cols { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
td.qty { white-space: nowrap; }
form.stocktake .input.count { width: 6rem; }
form.stocktake td.n { white-space: normal; }
form.stocktake .cols { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-end; }

.split-rows { display: grid; gap: 1rem; }
.extra-outputs .cols { margin-top: .75rem; }
.carbon-fields { border: 1px solid var(--border); border-radius: .5rem; padding: .75rem 1rem; margin: 0; }
.carbon-fields legend { font-size: .875rem; font-weight: 600; padding: 0 .25rem; }

/* Alerts on the dashboard and batch pages */
.alerts { list-style: none; padding: 0; margin: 0 0 1rem; }
.alerts li { margin: .4rem 0; line-height: 1.4; }
.alerts .tag { margin-right: .35rem; }
.planned-stale { margin-top: 1rem; }
.chart .dot.jar { stroke: var(--surface); stroke-width: 1; fill: var(--sg); }
.chart .dot.jar.foreshots { fill: var(--error); } .chart .dot.jar.heads { fill: var(--warning); }
.chart .dot.jar.hearts { fill: var(--success); } .chart .dot.jar.tails { fill: var(--text-2); }
.chart .dot.jar.undecided { fill: var(--surface); stroke: var(--text-2); stroke-width: 1.5; }
.cutguide { max-width: none; margin: 0 0 1rem; line-height: 1.5; }
.undecided-note { border-inline-start: 4px solid var(--warning); }
.set-cuts tr.undecided td { background: color-mix(in srgb, var(--warning) 8%, transparent); }

/* Search box at the end of the header */
.top .top-search { flex: none; display: flex; align-items: center; }
.top .top-search input { width: 9rem; padding: .5rem .75rem; }
@media (max-width: 40rem) { .top .top-search input { width: 5.5rem; } }
/* Scan a label: a QR icon after the search box (order 2 on a phone keeps it before the menu button) */
.top .scan-link { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 2.5rem; height: 2.5rem;
  border: 1px solid var(--border); border-radius: .5rem; color: var(--text); }
.top .scan-link:hover, .top .scan-link[aria-current=page] { background: var(--surface-2); }
.top .scan-link:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (max-width: 66rem) { .top .scan-link { order: 2; width: 2.75rem; height: 2.75rem; } }
/* The Scan page: the camera view fills the width, up to a comfortable size */
.scan-view video { display: block; width: 100%; max-width: 32rem; aspect-ratio: 4 / 3; object-fit: cover; border-radius: .5rem; background: #000; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.scan .actions label.btn { cursor: pointer; position: relative; }
.scan .actions label.btn:focus-within { outline: 2px solid var(--focus); outline-offset: 2px; }

/* Bottle labels: real sizes in mm, as many to a sheet as fit */
.labels { display: flex; flex-wrap: wrap; gap: 2mm; }
.label { width: var(--w); height: var(--h); box-sizing: border-box; border: .2mm dashed #999; padding: 3mm; display: flex;
  gap: 2mm; background: #fff; color: #000; overflow: hidden; break-inside: avoid; page-break-inside: avoid; }
.label-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .8mm; }
.label-name { font-size: calc(var(--h) * .125); font-weight: 600; line-height: 1.1; }
.label-abv { font-size: calc(var(--h) * .085); }
.label-meta { font-size: calc(var(--h) * .058); line-height: 1.25; color: #333; }
.label-note { margin-top: auto; font-size: calc(var(--h) * .056); color: #333; }
.label-qr { flex: none; width: calc(var(--h) * .5); align-self: flex-end; }
.label-qr svg { width: 100%; height: auto; display: block; }
@media print { @page { size: A4; margin: 8mm; } .labels { gap: 0; } .label { border-color: #ccc; } }

/* Equipment: the parts a still is built from, one row per kind */
fieldset.parts .part-row { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem 1.25rem; padding: .35rem 0; border-bottom: 1px solid var(--border); }
fieldset.parts .part-row > .muted { flex: 0 0 9rem; font-size: .875rem; }
details.item > summary { margin: 0; }
details.item[open] > summary { margin-bottom: 1rem; }
fieldset.parts .stepper { display: inline-flex; align-items: center; gap: .25rem; }
fieldset.parts .stepper input.input { width: 3.5rem; flex: 0 0 3.5rem; min-width: 0; text-align: center; padding: .375rem .25rem; -moz-appearance: textfield; }
fieldset.parts .stepper input::-webkit-inner-spin-button, fieldset.parts .stepper input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
fieldset.parts .stepper .step { min-width: 2.25rem; padding: .25rem .5rem; font-size: 1rem; line-height: 1.25rem; }
fieldset.parts .part-row[hidden] { display: none; }
fieldset #polish-fields[hidden], fieldset #finish-fields[hidden] { display: none; }
#add-oak-form [data-oak-for][hidden] { display: none; }
fieldset.parts .off-type { flex-basis: 100%; color: var(--error); }
fieldset.parts input[type=radio] { width: 1.125rem; height: 1.125rem; margin: 0; accent-color: var(--link); }

/* Equipment table: retired gear greyed out */
.table tr.retired td { opacity: .55; }
.parts-table button.link { font-size: .875rem; font-weight: 400; }

/* Pop-ups: a wide one for long forms (editing a plan); forms inside sit flat, not in a card. */
.modal.modal-wide { max-width: 64rem; }
.modal form.card, .modal .tile { border: 0; box-shadow: none; padding: 0; background: transparent; }
.modal form.inline { display: flex; flex-direction: column; align-items: stretch; }
.modal form + form { margin-top: 1rem; }
.modal .table-pick { margin-top: .5rem; }
.modal form.stack { max-width: none; gap: 1rem; }
.modal form.stack > button, .modal form.stack > .btn { justify-self: start; }
@media print { [data-open], dialog.modal { display: none !important; } }
/* Button placement, the same on every page (tests/test_buttons.py checks it):
   - a header has the actions only, primary first; links to other pages go in .see-also under it;
   - a detail page has a .crumb back link above its title;
   - a pop-up ends in .foot: primary submit, then Cancel, then any delete pushed right in red outline.
   - Delete is never folded away: it's the last header button on a record's page and the last footer button
     in its Edit form, both opening the same delete pop-up (_macros.html delete_button / delete_dialog).
     The footer sticks to the bottom of a long pop-up so Save is always in view. */
.see-also { display: flex; flex-wrap: wrap; gap: 0 1.25rem; margin: .25rem 0 0; font-size: .875rem; font-weight: 500; }
.see-also a { display: inline-flex; align-items: center; min-height: 2.25rem; }
.actions .push { margin-left: auto; }
button.btn[data-close] { display: none; }
dialog button.btn[data-close], main:has(.crumb.back-to) button.btn[data-close] { display: inline-flex; }
.modal .foot { position: sticky; bottom: -1.5rem; z-index: 1; margin: .5rem -1.5rem 0; padding: .75rem 1.5rem; background: var(--surface); border-top: 1px solid var(--border); }
.modal form.alt { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--border); }
.modal td form.alt { margin: 0; padding: 0; border: 0; }
button.link.remove { color: var(--error); }
td:has(> form > button.remove), td.row-actions { text-align: right; }
td.row-actions .actions { justify-content: flex-end; }
body.print [data-open] { display: none; }

/* Settings: the cards are grouped into categories, one shown at a time (settings.html). On a wide screen the
   categories are a list down the left that stays put as you scroll; on a phone they're a drop-down above the cards. */
.settings-layout { margin-top: 1rem; }
.settings-nav { margin: 0 0 1rem; }
.settings-nav ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .25rem; }
.settings-nav li { margin: 0; }
.settings-nav a { display: block; padding: .5rem .75rem; border-radius: .5rem; color: var(--text); text-decoration: none; }
.settings-nav a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.settings-nav a b { display: block; font-weight: 500; }
.settings-nav a span { display: none; font-size: .75rem; color: var(--text-2); line-height: 1.33; }
.settings-nav a[aria-current] { background: var(--surface-2); color: var(--link); }
.settings-nav a[aria-current] b { font-weight: 600; }
.settings-pick { display: none; }
.settings-cat > .card:last-child { margin-bottom: 0; }
.settings-cat > section { scroll-margin-top: 5rem; }
@media (min-width: 48rem) {
  .settings-layout { display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: 2rem; align-items: start; }
  .settings-nav { position: sticky; top: 5rem; margin: 0; }
  .settings-nav ul { flex-direction: column; flex-wrap: nowrap; }
  .settings-nav a { padding: .625rem .875rem; }
  .settings-nav a span { display: block; margin-top: .125rem; }
}
@media (max-width: 47.9375rem) {
  .settings-layout.one-cat .settings-nav ul { display: none; }
  .settings-layout.one-cat .settings-pick { display: grid; gap: .25rem; font-weight: 500; }
  .settings-pick .select { width: 100%; }
}
section.tile > h2:first-child, section.tile > .head:first-child > h2 { margin-top: 0; }

/* Settings is a gear at the end of the bar on a laptop, so the bar fits; on a phone it's a word in the menu. */
.top nav .nav-settings .nav-link { display: inline-flex; align-items: center; }
.top nav .nav-settings .gear { display: block; }
.top nav .nav-settings .nav-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (min-width: 40.0625rem) and (max-width: 66rem) { .top nav ul { grid-template-columns: repeat(3, 1fr); } }
/* Small laptops: tighten the bar so every section still fits on one row. */
@media (min-width: 66.0625rem) and (max-width: 72rem) {
  .top { gap: .5rem; }
  .top nav .nav-link { padding-left: .4rem; padding-right: .4rem; font-size: .875rem; }
  .top .top-search input { width: 7rem; }
}
/* The menu button and group headings only show on a phone. */
.menu-toggle { display: none; align-items: center; justify-content: center; width: 2.75rem; height: 2.75rem; padding: 0; border: 1px solid var(--border);
  border-radius: .5rem; background: transparent; color: var(--text); cursor: pointer; }
.menu-toggle:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.top.menu-open .menu-toggle { background: var(--surface-2); }
.top nav .nav-group { display: none; }
/* Phones. The header is brand, search and a menu button that opens every section as a grouped panel.
   A strip or table with more to the side fades at that edge (base.html sets .more-left / .more-right),
   so it's plain there is more to see. */
.top nav.more-right, .scroll.more-right { -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent); mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent); }
.top nav.more-left, .scroll.more-left { -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 2.5rem), transparent); mask-image: linear-gradient(to left, #000 calc(100% - 2.5rem), transparent); }
.top nav.more-left.more-right, .scroll.more-left.more-right { -webkit-mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent); mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent); }
/* A fieldset is as wide as its widest field by default, which pushed long forms (a plan) off the screen. */
fieldset { min-width: 0; }
.select, .input, .textarea { max-width: 100%; }
code { overflow-wrap: anywhere; }
input[type=file] { max-width: 100%; }
form.inline > label { min-width: 0; max-width: 100%; }
/* Phones and tablets. The header is brand, search and a menu button that opens every section as a grouped panel;
   below 66rem (1056 px, so an iPad either way up) the sections don't fit on one row. */
@media (max-width: 66rem) {
  .top { flex-wrap: wrap; gap: .5rem; padding: .5rem 1rem; }
  .top .brand { flex: 1; }
  .top .top-search { order: 2; }
  .top .top-search input { width: 8.5rem; }
  .top .menu-toggle { display: inline-flex; order: 3; }
  /* The sections drop down under the header as a panel, grouped, two to a row. */
  .top nav { display: none; order: 4; flex: 0 0 100%; overflow: visible; -webkit-mask-image: none; mask-image: none; padding: .25rem 0 .5rem; }
  .top.menu-open nav { display: block; }
  .top nav ul { display: grid; grid-template-columns: 1fr 1fr; gap: .125rem .5rem; }
  .top nav .nav-group { display: block; grid-column: 1 / -1; margin: .75rem 0 .125rem; padding: 0 .625rem; font-size: .75rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: .04em; color: var(--text-2); }
  .top nav .nav-group:first-child { margin-top: .25rem; }
  .top nav .nav-link { padding: .75rem .625rem; font-size: 1rem; }
  .top nav .nav-link[aria-current=page] { background: var(--surface-2); }
  .top nav .nav-settings .gear { display: none; }
  .top nav .nav-settings .nav-label { position: static; width: auto; height: auto; overflow: visible; clip: auto; }
}
@media (max-width: 40rem) {
  main { padding-left: .75rem; padding-right: .75rem; }
  .btn { white-space: normal; text-align: center; }
  /* Tables keep their columns readable and scroll sideways, instead of squeezing every word
     onto its own line. Figures stay narrow; codes and links stay on one line;
     a cell of long text (base.html marks it .long or .longer) gets room for a sentence. */
  .table td, .table th, .table thead th, .table tfoot td { padding-left: .75rem; padding-right: .75rem; }
  .scroll > .table:not(.jars) td:where(:not(.n):not(:has(> input[type=checkbox])):not(:has(> form))) { min-width: 7.5rem; }
  .scroll > .table:not(.jars) td.long { min-width: 15rem; }
  .scroll > .table:not(.jars) td.longer { min-width: 19rem; }
  .scroll > .table:not(.jars) td a { white-space: nowrap; }
  .scroll > .table:not(.jars) td .badge { white-space: nowrap; }
  /* Pop-ups use nearly the whole screen. */
  .modal { width: calc(100% - 1rem); max-width: none; max-height: calc(100dvh - 1rem); padding: 1rem; }
  .modal.modal-wide { max-width: none; }
  .modal .foot { bottom: -1rem; margin: .5rem -1rem 0; padding: .75rem 1rem; }
}
/* On a touch screen, text buttons (remove, add another lot) get a finger-sized target. */
@media (pointer: coarse) {
  button.link { padding-top: .5rem; padding-bottom: .5rem; }
  /* Fingers need about 44 px: buttons, fields, the pop-up ×, fold-outs, and short text buttons like "edit". */
  .btn, .input, .select { min-height: 2.75rem; }
  .btn { min-width: 2.75rem; justify-content: center; }
  .modal-close { width: 2.75rem; height: 2.75rem; margin: -.375rem -.375rem -.375rem 0; }
  button.link { min-height: 2.75rem; min-width: 2.75rem; padding-inline: .375rem; }
  summary { padding-block: .625rem; }
  /* A tick box alone in a table cell: the whole cell is the target (base.html passes the tap on). */
  td:has(> input[type=checkbox]:only-child) { cursor: pointer; }
  /* iPhones zoom the page in on any field with text smaller than 16 px and leave it zoomed. */
  input, select, textarea, .input, .select, .textarea { font-size: max(1rem, 16px); }
}
/* Phones: the Save at the end of a long form stays at the bottom of the screen while you fill it in, like
   a pop-up's footer does. */
@media (max-width: 40rem) {
  form:not(dialog *) > .actions.foot { position: sticky; bottom: 0; z-index: 4; padding: .625rem 0; background: var(--bg);
    border-top: 1px solid var(--border); }
  :is(.card form, form.card):not(dialog *) > .actions.foot { background: var(--surface); }
}
/* Phones: the thing you do over and over on a page (log a reading, log a jar) is one tap from anywhere on it. */
.quick-action { display: none; }
@media (max-width: 40rem) {
  .quick-action { display: inline-flex; position: fixed; right: 1rem; bottom: calc(1rem + env(safe-area-inset-bottom)); z-index: 6;
    min-height: 3rem; padding: 0 1.25rem; border-radius: 9999px; box-shadow: 0 .25rem .75rem rgb(0 0 0 / .25); }
  .quick-action.gone { display: none; }
  /* A header button the page's floating button already does (dashboard Log readings) isn't shown twice. */
  .phone-hidden { display: none; }
}

/* Batches filter: status chips (the tick boxes hidden behind pills), quick links, then recipe/date/search. */
form.filters { display: grid; gap: .75rem; margin: 1rem 0; padding: 1rem; background: var(--surface); border: 1px solid var(--border); border-radius: .5rem; }
form.filters fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
form.filters legend { font-size: .875rem; font-weight: 500; margin-bottom: .5rem; padding: 0; }
.chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.chips legend { width: 100%; }
label.chip { flex-direction: row; align-items: center; gap: .375rem; min-height: 2.25rem; padding: 0 .875rem; border: 1px solid var(--border);
  border-radius: 9999px; background: var(--bg); cursor: pointer; text-transform: capitalize; font-weight: 500; user-select: none; }
label.chip input[type=checkbox] { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
label.chip .count { font-size: .75rem; color: var(--text-2); }
label.chip:has(input:checked) { background: #1c64f2; border-color: #1c64f2; color: #fff; }
label.chip:has(input:checked) .count { color: #dbeafe; }
label.chip:has(input:focus-visible) { box-shadow: 0 0 0 4px #c3ddfd; }
form.filters .quick { display: flex; flex-wrap: wrap; gap: .25rem 1.25rem; font-size: .875rem; font-weight: 500; }
form.filters .quick a { display: inline-flex; align-items: center; min-height: 2rem; }
form.filters .fields { display: flex; flex-wrap: wrap; gap: .75rem 1rem; align-items: flex-end; }
form.filters .fields .grow { flex: 1 1 12rem; }
form.filters .hint { margin: 0; font-size: .8125rem; }
form.filters details.more > summary { margin: 0 0 .5rem; font-size: .875rem; font-weight: 500; min-height: 2rem; display: list-item; }
@media (max-width: 640px) {
  form.filters .fields > label:not(.grow) { flex: 1 1 calc(50% - .5rem); }
  form.filters .fields > label.recipe { flex-basis: 100%; }
  form.filters .fields .input, form.filters .fields .select { width: 100%; min-width: 0; }
  form.filters .fields > label { min-width: 0; }
  form.filters .fields .btn { flex: 1 1 100%; }
}

/* Batches table tick boxes and the bar of things to do to every ticked batch. It sticks to the bottom of the
   screen while the table runs on below, so it's there however far down you tick. */
.batches-table th.tick, .batches-table td.tick { width: 1%; padding-right: 0; }
.batches-table th.tick > input[type=checkbox] { width: 2.25rem; height: 1.25rem; vertical-align: middle; }
.batches-table tr.ticked td { background: var(--surface); }
.bulk-bar { position: sticky; bottom: 0; z-index: 5; display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem;
  margin: .75rem 0 0; padding: .75rem 1rem; background: var(--bg); border: 1px solid var(--border); border-radius: .5rem; }
.bulk-bar form.inline { display: flex; gap: .5rem; margin: 0; }
.bulk-bar .select { inline-size: auto; min-width: 10rem; }
.bulk-bar .bulk-some, .bulk-bar.active .bulk-none { display: none; }
.bulk-bar.active .bulk-some { display: inline; }
.bulk-bar.active { border-color: var(--link); }
/* Wide screens show every action in a row; on a phone it's one line: the count, Next step, More and Delete, with
   More opening the rest above the bar. Nothing ticked, it's just a short hint that doesn't stick. */
.bulk-bar .bulk-more { display: contents; }
.bulk-bar .bulk-more-toggle, .bulk-bar .phone-only { display: none; }
@media (max-width: 40rem) {
  .bulk-bar { position: static; flex-wrap: nowrap; gap: .5rem; padding: .5rem .75rem; }
  .bulk-bar:not(.active) > :not(.bulk-none) { display: none; }
  .bulk-bar.active { position: sticky; box-shadow: 0 -.25rem .75rem rgb(0 0 0 / .12); }
  .bulk-bar .wide-only { display: none; }
  .bulk-bar .phone-only { display: inline; }
  .bulk-bar .bulk-some { margin-right: auto; white-space: nowrap; }
  .bulk-bar .btn { padding-inline: .75rem; white-space: nowrap; }
  .bulk-bar .bulk-more-toggle { display: inline-flex; }
  .bulk-bar .bulk-more { display: none; position: absolute; left: 0; right: 0; bottom: calc(100% + .25rem); flex-direction: column;
    gap: .5rem; padding: .75rem; background: var(--bg); border: 1px solid var(--link); border-radius: .5rem;
    box-shadow: 0 -.25rem .75rem rgb(0 0 0 / .12); }
  .bulk-bar.more-open .bulk-more { display: flex; }
  .bulk-bar .bulk-more form.inline { width: 100%; }
  .bulk-bar .bulk-more form.inline > .btn, .bulk-bar .bulk-more > .btn { flex: 1; justify-content: center; }
  .bulk-bar .bulk-more .select { flex: 1; min-width: 0; }
}
/* Cellar: the same bar for ticked lots, hidden until something is ticked and moved under the table ticked in. */
.bulk-bar[hidden] { display: none; }
.pick-bar { box-shadow: 0 -.25rem .75rem rgb(0 0 0 / .12); }
.pick-bar .pick-clear { margin-left: auto; }
.pick-table tr.ticked td { background: var(--surface); }
@media (max-width: 40rem) { .pick-bar .pick-clear { margin-left: 0; } }
@media (max-width: 22.5rem) { .bulk-bar { gap: .375rem; padding-inline: .5rem; } .bulk-bar .btn { padding-inline: .5rem; } }

/* Still charge table: tick what goes in, running total and boiler warnings underneath. */
.charge { min-width: 0; }  /* a grid child: without this the wide table stretches the whole form on a phone */
/* A form built round a lot table (bottling, a finishing step, a still run) uses the whole page on a big screen,
   so the table's columns and each lot's steps fit without scrolling sideways. */
@media (min-width: 75rem) { form.stack:has(> .charge) { max-width: none; } }
.charge-table .steps-through { margin-top: .25rem; font-size: .75rem; color: var(--text-2); line-height: 1.4; }
.charge-table .steps-through a { color: inherit; text-decoration: underline dotted; }
.charge-table .steps-through a:hover { color: var(--link); }
.charge-table tr.group th { background: var(--surface-2); font-weight: 600; text-align: left; padding-top: .75rem; }
.charge-table tr.pick-row { cursor: pointer; }
.charge-table tr.pick-row.on td { background: color-mix(in srgb, var(--success) 10%, transparent); }
.charge-table input.charge-l { min-width: 6rem; }
.charge-total { margin-top: .75rem; }
.charge-total .sum { margin: 0; }
.charge-total .warns { margin: .5rem 0 0; padding-left: 1.25rem; }
.charge-total .warns:empty { display: none; }
.charge-total.warn, .water-note.warn { border-left: 4px solid var(--warning); }
.water-note { margin: 0; } .water-note .muted { display: block; margin-top: .25rem; font-size: .8125rem; }

/* Settings: the pre-run safety checklist editor, one box per check with move and remove buttons */
.check-edit { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; counter-reset: check; }
.check-edit-row { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .5rem; counter-increment: check; }
.check-edit-row::before { content: counter(check) "."; min-width: 1.5rem; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-2); }
.check-edit-blank::before { content: "+"; }
.check-edit-row .input { flex: 1 1 16rem; min-width: 0; }
.check-edit-tools { display: inline-flex; gap: .125rem; flex: none; margin-left: auto; }
.check-edit-tools .btn { min-width: 2.25rem; padding-inline: .5rem; }

/* Fermenters: one card per named fermenter, with what's in it and how far its ferment has got. */
.grid.fermenters { margin-bottom: 1rem; }
.grid.fermenters.one { grid-template-columns: minmax(0, 32rem); }
.fermenter-card { gap: .5rem; }
.fermenter-head { display: flex; justify-content: space-between; align-items: center; gap: .5rem; }
.fermenter-head h3 { margin: 0; font-size: 1.125rem; }
.fermenter-size, .fermenter-empty { margin: 0; font-size: .875rem; }
.fermenter-batch { gap: .375rem; padding-top: .5rem; border-top: 1px solid var(--border); }
.fermenter-figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr)); gap: .25rem .75rem; margin: 0; }
.fermenter-figures dt { font-size: .75rem; color: var(--text-2); }
.fermenter-figures dd { margin: 0; font-variant-numeric: tabular-nums; }
.fermenter-progress { display: flex; flex-direction: column; gap: .125rem; }
.fermenter-progress progress { width: 100%; height: .5rem; accent-color: var(--sg); }
.fermenter-card .hint { margin: 0; }
/* Log readings for all fermenters: one column per fermenter, a row per figure. The row names stay in view while
   the fermenters scroll sideways on a phone. */
.log-all-when { max-width: 16rem; }
.log-all-table th[scope=col] { vertical-align: bottom; text-transform: none; letter-spacing: 0; }
.log-all-table th[scope=col] b, .log-all-table th[scope=col] span { display: block; white-space: nowrap; }
.log-all-table th[scope=col] b { color: var(--text); font-size: .9375rem; }
.log-all-table th[scope=row] { white-space: nowrap; font-weight: 600; }
.log-all-table td { min-width: 7.5rem; vertical-align: top; }
.log-all-table td .input { width: 100%; }
.log-all-table td .hint { display: block; margin: .25rem 0 0; white-space: nowrap; }
.log-all-table :is(thead th, tbody th):first-child { position: sticky; left: 0; z-index: 1; }
.log-all-table tbody th { background: var(--surface); }
@media (max-width: 40rem) {
  .scroll > .table.log-all-table td { min-width: 6.5rem; }
  .table.log-all-table :is(thead th, tbody th, td) { padding-left: .375rem; padding-right: .375rem; }
}
.abv-flag { color: #b45309; cursor: help; }
/* Rebuy alert toggle on the Ingredients list: a small row toggle that saves when flipped. */
form.rebuy-toggle { margin: 0; display: inline; }
form.rebuy-toggle input[type=checkbox] { width: 2.25rem; height: 1.25rem; vertical-align: middle; }
form.rebuy-toggle input[type=checkbox]::before { width: 1rem; height: 1rem; }
form.rebuy-toggle input[type=checkbox]:checked::before { transform: translateX(1rem); }

/* Sortable tables: the heading is a button with an arrow showing the current order. */
.table thead th[aria-sort] { padding: 0 !important; }
.table th button.sort { all: unset; box-sizing: border-box; display: inline-flex; align-items: center; gap: .25rem; width: 100%;
  min-height: 44px; padding: .5rem .75rem; cursor: pointer; font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit; }
.table th.n button.sort { justify-content: flex-end; }
.table th button.sort::after { content: "↕" / ""; opacity: .35; font-size: .85em; }
.table th[aria-sort=ascending] button.sort::after { content: "▲" / ""; opacity: 1; }
.table th[aria-sort=descending] button.sort::after { content: "▼" / ""; opacity: 1; }
.table th button.sort:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; border-radius: .25rem; }
/* Recipe ingredient lines: the ☰ handle you drag a line by. touch-action stops the page scrolling under a
   finger that is dragging; the row being dragged is lifted a little. */
td.order, .scroll > .table:not(.jars) td.order { width: 1%; min-width: 0; padding-right: 0; }
.drag-handle { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem;
  padding: 0; border: 0; border-radius: .375rem; background: none; color: var(--text); opacity: .55; cursor: grab;
  touch-action: none; }
.drag-handle:hover, .drag-handle:focus-visible { opacity: 1; background: var(--border); }
tr.dragging { position: relative; z-index: 2; box-shadow: 0 4px 14px rgba(0, 0, 0, .18); }
tr.dragging > td { background: var(--surface); }
tr.dragging .drag-handle { cursor: grabbing; }
@media (pointer: coarse) { .drag-handle { width: 2.75rem; height: 2.75rem; } }
/* Keep edit and remove side by side, so a line on a phone is one finger tall, not two. */
#recipe-items td.row-actions .actions { flex-wrap: nowrap; }

/* Login page (app/auth.py). */
.login-page { max-width: 24rem; padding-top: 12vh; }
.login-card h1 { margin: 0; }
