Files
beer_data/src/flask/static/css/app.css
T
hermes 7dd39190f1 fix(ui): mobile pop-out for the advice, and tables that fit a phone
The brewing advice is several hundred characters.  In a table cell it
pushed the table past the width of a phone, so the column was clipped
off the right edge and the advice could not be read without sideways
scrolling.

The advice is now a compact trigger in the cell and the text is in a
floating panel that opens on hover (desktop) or on tap (phone).

The panel is position:fixed and anchored by the script.  Absolutely
positioned inside the cell it was clipped by the table's own scroll
container, and the advice was sliced in half by the card's edge.  It
flips above the trigger when there is no room below.

The tables now reflow into stacked cards on a narrow screen, with each
value labelled by its column name.  A seven column table does not fit a
phone, and it used to scroll sideways inside its wrapper, so the
columns on the right were off the screen.

Also: the header wraps onto two rows so the nav tabs are not clipped,
the point scale says 'points' rather than 'pts', and the reading count
on the beer card does not orphan its word.
2026-11-09 20:57:34 +10:00

1005 lines
28 KiB
CSS

/* ==========================================================================
Brew Log — design system
Beer-house palette: warm amber/copper on near-black, with a condensed
display face (Anton) for headings and Inter for everything else.
Palette taken from the brewery-128 template:
--primary #be7f39 (amber / copper)
--primary-dark #0e0e0e
--black-primary #212024
--black-secondary #161616
--gray #e9e9e9
--dark-gray #afafaf
--paragraph-gray #535353
========================================================================== */
/* ------------------------------------------------------------------ fonts */
@font-face {
font-family: 'Anton';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('../fonts/anton-latin.woff2') format('woff2');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url('../fonts/inter-latin-400.woff2') format('woff2');
}
/* ----------------------------------------------------------------- tokens */
:root {
/* surfaces */
--bg: #121110;
--bg-raised: #1c1a19;
--bg-raised-2: #242120;
--bg-input: #161514;
/* lines */
--border: #332e2a;
--border-strong: #4a4239;
/* text */
--text: #f2ede8;
--text-muted: #afafaf;
--text-faint: #7d746c;
/* brand */
--amber: #be7f39;
--amber-bright: #dda05c;
--amber-deep: #8f5f28;
--amber-dim: rgba(190, 127, 57, 0.14);
--amber-text: #e2b47c;
/* foam / highlights */
--foam: #f7f3ee;
--cream: #eef4f8;
/* status */
--warn: #e8a33d;
--warn-dim: rgba(232, 163, 61, 0.14);
--danger: #d9534f;
--danger-dim: rgba(217, 83, 79, 0.14);
--success: #7db902;
--success-dim: rgba(125, 185, 2, 0.14);
--radius: 10px;
--radius-sm: 6px;
--radius-lg: 16px;
--shadow: 0 1px 2px rgba(0, 0, 0, .45), 0 10px 30px rgba(0, 0, 0, .35);
--font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--display: 'Anton', 'Arial Narrow', Impact, sans-serif;
--mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
}
* { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
background: var(--bg);
color: var(--text);
font-family: var(--font);
font-size: 15px;
line-height: 1.55;
-webkit-font-smoothing: antialiased;
}
a { color: var(--amber-text); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { margin: 0 0 .5rem; line-height: 1.15; font-weight: 650; }
h1 { font-size: 1.65rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.02rem; }
p { margin: 0 0 .75rem; }
/* Display type: the condensed face, used sparingly for headings and figures. */
.display {
font-family: var(--display);
font-weight: 400;
letter-spacing: .01em;
text-transform: uppercase;
}
/* ---------------------------------------------------------------- topbar */
.topbar {
position: sticky;
top: 0;
z-index: 50;
background: rgba(18, 17, 16, .94);
backdrop-filter: blur(8px);
border-bottom: 1px solid var(--border);
}
.topbar__inner {
max-width: 1240px;
margin: 0 auto;
padding: .6rem 1.25rem;
display: flex;
align-items: center;
gap: 1.5rem;
}
.brand {
display: flex;
align-items: center;
gap: .55rem;
color: var(--text);
text-decoration: none;
}
.brand:hover { text-decoration: none; }
.brand__mark {
font-size: 1.4rem;
line-height: 1;
filter: drop-shadow(0 0 10px rgba(190, 127, 57, .35));
}
.brand__text {
font-family: var(--display);
font-size: 1.22rem;
letter-spacing: .04em;
text-transform: uppercase;
color: var(--amber-bright);
}
.nav { display: flex; gap: .25rem; flex: 1; }
.nav__link {
padding: .4rem .8rem;
border-radius: var(--radius-sm);
color: var(--text-muted);
font-size: .92rem;
font-weight: 500;
text-decoration: none;
transition: background .12s ease, color .12s ease;
}
.nav__link:hover { background: var(--bg-raised-2); color: var(--text); text-decoration: none; }
.nav__link.is-active {
background: var(--amber-dim);
color: var(--amber-text);
box-shadow: inset 0 -2px 0 var(--amber);
}
.topbar__logout { display: flex; align-items: center; gap: .6rem; }
.topbar__user {
color: var(--text-muted);
font-size: .85rem;
font-family: var(--mono);
padding: .15rem .5rem;
border: 1px solid var(--border);
border-radius: 999px;
}
/* ------------------------------------------------------------------ page */
.page {
max-width: 1240px;
margin: 0 auto;
padding: 1.5rem 1.25rem 4rem;
}
.page--narrow { max-width: 460px; }
.page__head {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 1rem;
flex-wrap: wrap;
margin-bottom: 1.25rem;
}
.page__title {
margin: 0;
font-family: var(--display);
font-weight: 400;
font-size: 1.85rem;
letter-spacing: .02em;
text-transform: uppercase;
color: var(--text);
}
.page__sub { color: var(--text-muted); font-size: .9rem; margin: .15rem 0 0; }
/* ----------------------------------------------------------------- cards */
.card {
background: var(--bg-raised);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: var(--shadow);
position: relative;
}
/* A thin amber seam along the top of each card — the "label on the barrel" touch. */
.card::before {
content: '';
position: absolute;
inset: 0 0 auto 0;
height: 2px;
border-radius: var(--radius) var(--radius) 0 0;
background: linear-gradient(90deg, var(--amber-deep), var(--amber) 40%, transparent 85%);
opacity: .8;
}
.card__head {
padding: .9rem 1.1rem;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
flex-wrap: wrap;
}
.card__title {
margin: 0;
font-size: 1rem;
font-weight: 650;
letter-spacing: .01em;
}
.card__hint { color: var(--text-faint); font-size: .82rem; }
.card__body { padding: 1.1rem; }
.card__body--flush { padding: 0; }
.grid { display: grid; gap: 1rem; }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* The active-beer cards: fill the row whatever the number of brews. */
.grid--cards { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid--sidebar { grid-template-columns: minmax(0, 380px) minmax(0, 1fr); align-items: start; }
@media (max-width: 1000px) {
.grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--sidebar { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
.grid--2, .grid--3, .grid--4 { grid-template-columns: minmax(0, 1fr); }
.topbar__inner { flex-wrap: wrap; gap: .75rem; }
.nav { order: 3; width: 100%; overflow-x: auto; }
.page__title { font-size: 1.5rem; }
}
/* ----------------------------------------------------------------- stats */
.stat {
background: var(--bg-raised);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: .85rem 1rem;
}
.stat__label {
color: var(--text-faint);
font-size: .72rem;
text-transform: uppercase;
letter-spacing: .09em;
font-weight: 600;
}
.stat__value {
font-family: var(--display);
font-weight: 400;
font-size: 1.75rem;
letter-spacing: .02em;
line-height: 1.2;
color: var(--amber-bright);
}
.stat__meta { color: var(--text-muted); font-size: .83rem; }
/* ----------------------------------------------------------------- forms */
.field { margin-bottom: .9rem; }
.field__label {
display: block;
font-size: .74rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .09em;
color: var(--text-muted);
margin-bottom: .3rem;
}
.field__hint { color: var(--text-muted); font-size: .8rem; margin-top: .25rem; }
.field__error { color: var(--danger); font-size: .8rem; margin-top: .25rem; }
input[type="text"], input[type="password"], input[type="number"],
input[type="date"], input[type="email"], textarea, select {
width: 100%;
padding: .5rem .65rem;
background: var(--bg-input);
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
color: var(--text);
font-family: inherit;
font-size: .92rem;
transition: border-color .12s ease, box-shadow .12s ease;
}
input:focus, textarea:focus, select:focus {
outline: none;
border-color: var(--amber);
box-shadow: 0 0 0 3px var(--amber-dim);
}
input::placeholder, textarea::placeholder { color: var(--text-faint); }
textarea { resize: vertical; min-height: 5rem; }
.checkbox {
display: flex;
align-items: center;
gap: .55rem;
font-size: .9rem;
color: var(--text);
cursor: pointer;
}
/* The native checkbox is a white square on a near-black page — replace it. */
.checkbox input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
width: 1.05rem;
height: 1.05rem;
margin: 0;
flex: 0 0 auto;
border: 1px solid var(--border-strong);
border-radius: 4px;
background: var(--bg-input);
cursor: pointer;
position: relative;
transition: background .12s ease, border-color .12s ease;
}
.checkbox input[type="checkbox"]:hover { border-color: var(--amber); }
.checkbox input[type="checkbox"]:checked {
background: var(--amber);
border-color: var(--amber);
}
.checkbox input[type="checkbox"]:checked::after {
content: '';
position: absolute;
left: .32rem;
top: .07rem;
width: .28rem;
height: .55rem;
border: solid #17110a;
border-width: 0 2px 2px 0;
transform: rotate(43deg);
}
.checkbox input[type="checkbox"]:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--amber-dim);
}
/* Hide the native number spinners — the light spinner widgets jar badly
against the dark theme. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type="number"] { -moz-appearance: textfield; }
/* The native date picker's calendar icon is near-black on near-black. */
input[type="date"]::-webkit-calendar-picker-indicator {
filter: invert(0.75) sepia(1) saturate(3) hue-rotate(350deg) brightness(1.1);
cursor: pointer;
opacity: .7;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }
/* Dark scrollbars to match the page. */
* {
scrollbar-width: thin;
scrollbar-color: var(--border-strong) var(--bg);
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb {
background: var(--border-strong);
border-radius: 6px;
border: 2px solid var(--bg);
}
::-webkit-scrollbar-thumb:hover { background: var(--amber-deep); }
/* A figure that should read as a number, not as body text. */
.strong { font-weight: 650; color: var(--text); }
.field-row { display: flex; gap: .75rem; }
.field-row > * { flex: 1; }
/* --------------------------------------------------------------- buttons */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: .4rem;
padding: .5rem .95rem;
border: 1px solid transparent;
border-radius: var(--radius-sm);
background: var(--amber);
color: #17110a;
font-family: inherit;
font-size: .85rem;
font-weight: 650;
letter-spacing: .01em;
cursor: pointer;
text-decoration: none;
transition: filter .12s ease, background .12s ease, border-color .12s ease;
}
.btn:hover { filter: brightness(1.12); text-decoration: none; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn--ghost {
background: transparent;
border-color: var(--border-strong);
color: var(--text-muted);
}
.btn--ghost:hover { background: var(--bg-raised-2); color: var(--text); }
.btn--danger { background: transparent; border-color: var(--danger); color: var(--danger); }
.btn--danger:hover { background: var(--danger-dim); }
.btn--sm { padding: .3rem .6rem; font-size: .78rem; }
.btn--block { width: 100%; }
.btn-row { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
/* ---------------------------------------------------------------- tables */
.table-wrap { overflow-x: auto; }
table.data {
width: 100%;
border-collapse: collapse;
font-size: .88rem;
}
table.data th {
text-align: left;
padding: .55rem .8rem;
color: var(--text-faint);
font-size: .7rem;
font-weight: 650;
text-transform: uppercase;
letter-spacing: .08em;
border-bottom: 1px solid var(--border);
background: var(--bg-raised-2);
white-space: nowrap;
}
table.data td {
padding: .6rem .8rem;
border-bottom: 1px solid var(--border);
vertical-align: top;
}
table.data tr:last-child td { border-bottom: none; }
table.data tbody tr:hover { background: var(--bg-raised-2); }
table.data .num { font-family: var(--mono); text-align: right; white-space: nowrap; }
table.data .comment { color: var(--text-muted); font-size: .84rem; }
/* On a narrow screen the tables reflow into stacked cards.
A seven-column table does not fit a phone. It was left to scroll
sideways inside its wrapper, which meant the columns on the right were
off the screen and the brewer had to pan the table to see them.
Each row becomes a card: the header cell becomes a label above its
value, and the cells stack. */
@media (max-width: 720px) {
/* The header wraps onto two rows on a phone: the brand and the
sign-out on the first, the nav tabs on the second where they get
the full width and scroll sideways if they still do not fit.
They used to sit on one row with the brand and the sign-out, and
the last tab was cut off mid-word. */
.topbar__inner {
flex-wrap: wrap;
row-gap: .5rem;
}
.brand {
order: 1;
}
.topbar__logout {
order: 2;
margin-left: auto;
}
.nav {
order: 3;
flex: 1 0 100%;
overflow-x: auto;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
/* A fade at the right edge so a clipped tab reads as
scrollable rather than broken. */
-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent 100%);
mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent 100%);
}
.nav::-webkit-scrollbar {
display: none;
}
.nav__link {
flex-shrink: 0;
}
/* Tighter tabs, so all four fit on a phone without scrolling.
They still scroll if they have to. */
.nav__link {
padding: .35rem .55rem;
font-size: .8rem;
letter-spacing: .01em;
}
.table-wrap {
overflow-x: visible;
}
table.data,
table.data tbody,
table.data tr,
table.data td {
display: block;
width: auto;
}
table.data thead {
/* HIDDEN in the stacked layout. Each cell shows its column
name as a label, so the header row would be a duplicate - and
it was 230px of the first card. */
display: none;
}
table.data tr {
border: 1px solid var(--border);
border-radius: 8px;
margin-bottom: .75rem;
padding: .25rem .1rem;
background: var(--bg-raised-2);
}
table.data tbody tr:hover {
background: var(--bg-raised-2);
}
table.data th {
display: block;
border-bottom: 1px solid var(--border);
}
table.data td {
display: grid;
grid-template-columns: 8.5rem 1fr;
gap: .5rem;
align-items: baseline;
padding: .45rem .7rem;
border-bottom: 1px solid rgba(255, 255, 255, .04);
text-align: left;
}
table.data td::before {
/* The column heading, shown as the row's label. */
content: attr(data-label);
font-size: .65rem;
font-weight: 650;
letter-spacing: .07em;
text-transform: uppercase;
color: var(--text-faint);
}
table.data td.num {
text-align: left;
}
table.data td.right,
table.data td:empty {
grid-template-columns: 1fr;
}
table.data td.right::before {
content: none;
}
/* A cell with nothing in it must not leave a gap. */
table.data td:empty {
display: none;
}
}
/* ----------------------------------------------------------------- chips */
.chip {
display: inline-flex;
align-items: center;
gap: .3rem;
padding: .12rem .5rem;
border-radius: 999px;
font-size: .74rem;
font-weight: 600;
letter-spacing: .02em;
white-space: nowrap;
}
.chip--active { background: var(--amber-dim); color: var(--amber-text); }
.chip--done { background: rgba(175, 175, 175, .13); color: var(--text-muted); }
.chip--warn { background: var(--warn-dim); color: var(--warn); }
.chip--danger { background: var(--danger-dim); color: var(--danger); }
.chip--good { background: var(--success-dim); color: var(--success); }
/* A run whose readings are impossible: shown in the table so it can be
corrected, but marked as not counted in the averages. */
.data tbody tr.is-suspect td {
color: var(--text-muted);
background: rgba(232, 163, 61, .06);
}
.chip--tap {
background: var(--bg-raised-2);
border: 1px solid var(--amber-deep);
color: var(--amber-text);
font-family: var(--mono);
}
/* --------------------------------------------------------------- flashes */
.flashes { display: flex; flex-direction: column; gap: .5rem; margin-bottom: 1rem; }
.flash {
padding: .6rem .9rem;
border-radius: var(--radius-sm);
border: 1px solid var(--border);
background: var(--bg-raised);
font-size: .9rem;
}
.flash--success { border-color: rgba(125, 185, 2, .45); background: var(--success-dim); color: #c3e08a; }
.flash--error { border-color: rgba(217, 83, 79, .45); background: var(--danger-dim); color: #f0a8a6; }
.flash--warning { border-color: rgba(232, 163, 61, .45); background: var(--warn-dim); color: #f2c880; }
.flash--info { border-color: rgba(190, 127, 57, .45); background: var(--amber-dim); color: var(--amber-text); }
/* ---------------------------------------------------------------- login */
.login {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem 1rem;
background:
radial-gradient(900px 480px at 50% -10%, rgba(190, 127, 57, .13), transparent 62%),
var(--bg);
}
.login__card {
width: 100%;
max-width: 380px;
background: var(--bg-raised);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 2rem;
box-shadow: var(--shadow);
position: relative;
}
.login__card::before {
content: '';
position: absolute;
inset: 0 0 auto 0;
height: 3px;
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
background: linear-gradient(90deg, var(--amber-deep), var(--amber-bright), var(--amber-deep));
}
.login__mark { font-size: 2.4rem; line-height: 1; }
.login__title {
margin: .6rem 0 .15rem;
font-family: var(--display);
font-weight: 400;
font-size: 1.9rem;
letter-spacing: .03em;
text-transform: uppercase;
color: var(--amber-bright);
}
.login__sub { color: var(--text-muted); font-size: .88rem; margin-bottom: 1.4rem; }
/* ----------------------------------------------------------- active card */
.brew-card {
background: var(--bg-raised);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1rem 1.1rem;
display: flex;
flex-direction: column;
gap: .75rem;
position: relative;
overflow: hidden;
}
.brew-card::before {
content: '';
position: absolute;
inset: 0 0 auto 0;
height: 2px;
background: linear-gradient(90deg, var(--amber-deep), var(--amber) 45%, transparent 90%);
opacity: .75;
}
.brew-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: .75rem; }
.brew-card__name { font-weight: 650; font-size: 1.02rem; margin: 0; }
.brew-card__meta { color: var(--text-muted); font-size: .82rem; font-family: var(--mono); }
.brew-card__stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: .6rem; }
/* The three stats sit side by side, so their captions line up. One
caption ("needs 2nd reading") is two lines and the others are one,
which left the baselines ragged. */
.brew-card__stat {
display: flex;
flex-direction: column;
}
.brew-card__stat .stat__label { font-size: .68rem; }
.brew-card__stat .stat__value { font-size: 1.3rem; }
.brew-card__stat .stat__meta { margin-top: auto; }
.brew-card__spark { height: 46px; }
/* The "start a new beer" tile — fills the last grid slot and gives the
page a way to begin a brew without hunting for the form. */
.brew-card--new {
align-items: center;
justify-content: center;
gap: .6rem;
text-align: center;
text-decoration: none;
color: var(--text-muted);
border-style: dashed;
border-color: var(--border-strong);
min-height: 180px;
}
.brew-card--new:hover {
border-color: var(--amber);
color: var(--text);
text-decoration: none;
}
.brew-card--new::before { display: none; }
.brew-card__new-mark {
display: flex;
align-items: center;
justify-content: center;
width: 2.4rem;
height: 2.4rem;
border: 1px solid var(--amber);
border-radius: 50%;
font-size: 1.35rem;
line-height: 1;
color: var(--amber);
}
.brew-card__new-text { display: flex; flex-direction: column; gap: .15rem; }
.brew-card__new-text strong { font-size: .95rem; }
.brew-card__spark--empty {
display: flex;
align-items: center;
font-style: italic;
padding: .35rem 0;
}
/* --------------------------------------------------------------- helpers */
.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.mono { font-family: var(--mono); }
.nowrap { white-space: nowrap; }
.small { font-size: .84rem; }
.tiny { font-size: .76rem; }
.center { text-align: center; }
.right { text-align: right; }
.stack > * + * { margin-top: .75rem; }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.row { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; }
.row--between { justify-content: space-between; }
.hidden { display: none !important; }
/* Spacing utilities. These exist so the templates carry no inline
`style=` attributes, which a strict Content-Security-Policy
(`style-src 'self'`) would block. */
.mb-lg { margin-bottom: 1.25rem; }
.mt-lg { margin-top: 2rem; }
.empty {
padding: 2.5rem 1rem;
text-align: center;
color: var(--text-faint);
}
.empty__icon { font-size: 2rem; display: block; margin-bottom: .5rem; opacity: .7; }
/* --------------------------------------------------------------- reading */
.reading-list { list-style: none; margin: 0; padding: 0; }
.reading-list__item {
display: flex;
gap: .75rem;
align-items: flex-start;
padding: .6rem 0;
border-bottom: 1px solid var(--border);
}
.reading-list__item:last-child { border-bottom: none; }
.reading-list__date {
font-family: var(--mono);
font-size: .82rem;
color: var(--text-muted);
flex: 0 0 5.5rem;
}
.reading-list__sg { font-family: var(--mono); font-weight: 650; flex: 0 0 4rem; }
.reading-list__body { flex: 1; min-width: 0; }
.reading-list__comment { color: var(--text-muted); font-size: .84rem; }
/* ------------------------------------------------------------- advice */
/* The LLM's advice. It sits next to the brewer's own comment, never
replaces it, and is visually distinct so the two are never confused. */
.advice {
display: block;
margin-top: .35rem;
padding: .5rem .65rem;
border-left: 2px solid var(--amber);
border-radius: 0 4px 4px 0;
background: var(--amber-dim);
color: var(--text);
font-size: .8125rem;
line-height: 1.5;
}
.advice__label {
display: block;
margin-bottom: .15rem;
font-size: .625rem;
font-weight: 600;
letter-spacing: .08em;
text-transform: uppercase;
color: var(--amber-text);
}
/* The advice on the active-beers card and the run detail page - the
full text, not the clamped table cell. */
.advice--reading {
margin-top: .5rem;
}
/* Advice that could not be generated - it says why. */
.advice--failed {
border-left-color: var(--danger);
background: var(--danger-dim);
color: var(--text-muted);
}
.advice--failed .advice__label {
color: var(--danger);
}
/* The advice in the table is a compact trigger that pops the full text
out on hover, focus or tap.
It used to be the text itself, clamped to four lines. The advice runs
to several hundred characters, and a cell that wide pushes the table
past the width of a phone, so the column ended up clipped off the
right edge and unreadable without sideways scrolling. */
.advice-cell {
position: relative;
width: 1%;
white-space: nowrap;
}
.advice-trigger {
display: inline-flex;
align-items: center;
gap: .35rem;
padding: .25rem .55rem;
border: 1px solid var(--amber);
border-radius: 999px;
background: var(--amber-dim);
color: var(--amber-text);
font: inherit;
font-size: .75rem;
line-height: 1.4;
cursor: pointer;
white-space: nowrap;
}
.advice-trigger:hover,
.advice-trigger:focus-visible {
background: var(--amber);
color: var(--bg);
}
.advice-trigger--failed {
border-color: var(--danger);
background: var(--danger-dim);
color: var(--danger);
}
.advice-trigger__icon {
font-size: .85em;
}
/* The pop-out.
It is `position: fixed` and anchored to the trigger by the script,
not absolutely positioned inside the cell. The table is a scroll
container, and an absolutely positioned panel inside it was clipped
by the container's own overflow - the advice was sliced in half by
the card's edge and the bottom border was cut off.
Fixed positioning takes it out of the table entirely, so it floats
above the page and is never cut by a scroll container. */
.advice-pop {
position: fixed;
z-index: 200;
display: none;
width: min(30rem, 92vw);
max-height: 70vh;
overflow-y: auto;
padding: .8rem .9rem;
border: 1px solid var(--amber);
border-radius: 8px;
background: var(--bg-raised);
box-shadow: 0 12px 32px rgba(0, 0, 0, .55);
text-align: left;
white-space: normal;
}
.advice-pop__head {
display: flex;
align-items: center;
justify-content: space-between;
gap: .5rem;
margin-bottom: .4rem;
}
.advice-pop__head .advice__label {
margin-bottom: 0;
}
.advice-pop__close {
border: 0;
background: none;
color: var(--text-muted);
font-size: 1.1rem;
line-height: 1;
cursor: pointer;
padding: 0 .15rem;
}
.advice-pop__close:hover {
color: var(--text);
}
.advice-pop__text {
margin: 0;
font-size: .8125rem;
line-height: 1.55;
color: var(--text);
}
/* The script opens and closes the panel, and places it. The CSS only
decides whether it is shown. */
.advice-pop.is-open {
display: block;
}
/* On a phone there is no hover, so the trigger is a button the script
toggles, and the panel is pinned to the middle of the screen so it is
readable whatever the table's width. */
@media (max-width: 720px) {
.advice-cell {
width: auto;
}
/* On a phone the panel is centred on the screen rather than
anchored to the trigger - there is not the room to float it
beside the cell, and the trigger may be near the edge. */
.advice-pop {
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%);
}
}