/* Nidodo components. The design language, in three rules:
 *
 * 1. Paper is for paper things. Only objects you could hold (.gcard, .reply,
 *    .paper) get the washed watercolour paper. App surfaces stay flat pastel.
 * 2. Lettering appears once: the names on the card (--nl-font-hand, Delius
 *    Swash Caps). Everything else speaks in Figtree, so the names are the
 *    one personal, picture-book thing on the page.
 * 3. Watercolour carries one meaning each, never decor: the rainbow emblem
 *    on the card, the heart for "got it" and "thank you", the sun for the
 *    birth, the moon for a paused list, and a charm on an onboarding
 *    question only where it says something (rattles, mobile, bunny).
 *    Progress is drawn, not painted.
 *
 * Colours come only from nidodo.css tokens. */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--nl-stock);
  color: var(--nl-ink);
  font: 400 1rem/1.55 var(--nl-font-body);
}

/* Before the parents pick a stock, the card lies on a table. */
body.on-table {
  background: var(--nl-table);
  color: var(--nl-table-ink);
}

::selection {
  background: var(--nl-stock-sunk);
  color: var(--nl-ink);
}

:focus-visible {
  outline: 2px solid var(--nl-ink);
  outline-offset: 3px;
}

a {
  color: var(--nl-ink);
  text-decoration-color: var(--nl-ink-soft);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 4px;
}

h1,
h2,
h3 {
  font-family: var(--nl-font-display);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.08;
  margin: 0;
  text-wrap: balance;
}

p {
  margin: 0;
  text-wrap: pretty;
}

/* Rule 1: paper things. Two real CC0 scans multiplied over the stock colour
 * (paths relative to this file). Paper objects set only background-color, so
 * nothing later resets the texture. */
.paper,
.gcard,
.reply {
  background-image: url('../../vendor/textures/paper-tooth.webp'), url('../../vendor/textures/paper-wash.webp');
  background-size: 512px auto, 640px 640px;
  background-blend-mode: multiply;
}
/* Multiply in dark mode too. The scans are near white: soft-light lifted a
   dark card to light grey under light text (measured 1.3:1). Multiply keeps
   the card's own dark colour (6.6:1 small text) and the tooth still shows. */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------------------------------------------------------------- app bar */

.bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  max-width: 1080px;
  margin: 0 auto;
  padding: 12px 16px;
  min-height: 60px;
}

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

.brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  color: inherit;
  text-decoration: none;
  font-family: var(--nl-font-display);
  font-weight: 600;
  font-size: 1.12rem;
  letter-spacing: -0.02em;
}

a.brand:focus-visible {
  outline: 2px solid var(--nl-ink);
  outline-offset: 4px;
  border-radius: 8px;
}
.brand svg {
  /* The dodo mark: below about 32px its eye and neck line close up. */
  width: 34px;
  height: 34px;
}

/* Language: one quiet line of text at the edge of a page, never in the bar.
   The current language is plain text; the others are text buttons with a
   full 44px tap height. */
.langline {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  column-gap: 0.15rem;
  font: 500 0.875rem/1.2 var(--nl-font-body);
  color: var(--nl-ink-soft);
}
.langline__item {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 0.4rem;
}
.langline span.langline__item {
  color: var(--nl-ink);
  font-weight: 650;
}
.langline button {
  font: inherit;
  color: inherit;
  border: 0;
  background: none;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 0.25em;
}
.langline button:hover {
  color: var(--nl-ink);
  text-decoration-color: currentColor;
}
.langline button:focus-visible {
  outline: 2px solid var(--nl-ink);
  outline-offset: -2px;
  border-radius: 6px;
}
.langline__sep {
  opacity: 0.6;
}
body.on-table .langline {
  color: color-mix(in oklch, var(--nl-table-ink) 78%, transparent);
}
body.on-table .langline span.langline__item,
body.on-table .langline button:hover {
  color: var(--nl-table-ink);
}

/* ---------------------------------------------------------------- the card */

.gcard {
  --tilt: -1.4deg;
  position: relative;
  width: 100%;
  max-width: 440px;
  aspect-ratio: 7 / 5;
  margin-inline: auto;
  /* Room at the bottom so the corner charm never touches the last line. */
  padding: 0 clamp(18px, 5vw, 30px) clamp(40px, 12vw, 52px);
  border-radius: 6px;
  background-color: var(--nl-card);
  color: var(--nl-ink);
  box-shadow: var(--nl-card-shadow);
  transform: rotate(var(--tilt));
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  align-items: start;
  text-align: center;
  transition: background-color 600ms cubic-bezier(0.16, 1, 0.3, 1), transform 600ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* A card without a painted emblem (the app until its own paintings are
   licensed): three rows, the names centred, equal air above and below. */
.gcard--plain {
  grid-template-rows: auto 1fr auto;
  padding-block: clamp(30px, 9vw, 44px);
}

/* Every page is the table now, so the card reads as an object everywhere:
   no lift needed. */

.gcard__frame {
  position: absolute;
  inset: 10px;
  border-radius: 3px;
  box-shadow: inset 0 0 0 1px var(--nl-card-line);
  pointer-events: none;
}

.gcard__expecting {
  font-size: clamp(0.85rem, 3.5vw, 0.98rem);
  letter-spacing: 0.01em;
  font-weight: 500;
  color: var(--nl-ink-soft);
  view-transition-name: card-expecting;
}

.gcard__names {
  align-self: center;
  font-family: var(--nl-font-hand);
  font-size: clamp(2.2rem, 11vw, 3.3rem);
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.08;
  /* Delius' tall swashes need air above and below. */
  margin-block: 8px;
  overflow-wrap: anywhere;
  view-transition-name: card-names;
}

.gcard__names .amp {
  color: var(--nl-paint);
  font-weight: 500;
}

.gcard__names.is-placeholder {
  color: var(--nl-ink-soft);
  font-weight: 500;
}

.gcard__due {
  white-space: pre-line;
  font-size: 0.9rem;
  color: var(--nl-ink-soft);
  view-transition-name: card-due;
}

/* Watercolour art: real paintings, placed, never imitated. */
.art {
  display: block;
  max-width: 100%;
  height: auto;
  user-select: none;
  pointer-events: none;
}

/* The emblem: one small painting above the text, in the card's first row. */
.gcard__emblem {
  justify-self: center;
  width: 54px;
  margin: 28px auto 6px;
}

.gcard__charm {
  position: absolute;
  right: -4px;
  bottom: -26px;
  width: 64px;
  transform: rotate(6deg);
  z-index: 1;
}
.gcard__charm.art--sun {
  width: 60px;
  bottom: -30px;
}

.gcard--small {
  aspect-ratio: auto;
  width: 100%;
  max-width: none;
  min-height: 0;
  padding: 0 20px 44px;
  --tilt: 0deg;
  gap: 6px;
}
.gcard--small.gcard--plain {
  padding-block: 28px;
}
.gcard--small .gcard__emblem {
  width: 44px;
  margin: 24px auto 2px;
}

/* The dodo is the mascot, not a theme element: always its own dusty blue.
   Its height is spelled out: an svg with height auto counts as 0 in the
   card's grid and would overflow onto the names. Scales with the card,
   since a 7:5 card on a phone has no room for the full size. */
.gcard__emblem.art--dodo-nest {
  --nl-h: 255;
  --nl-c: 0.038;
  --emblem-w: clamp(52px, 16vw, 76px);
  width: var(--emblem-w);
  height: calc(var(--emblem-w) * 570 / 590);
  margin-top: clamp(18px, 5vw, 30px);
}
.gcard--small .gcard__emblem.art--dodo-nest {
  --emblem-w: 58px;
  margin-top: 26px;
}
.gcard--small .gcard__names {
  font-size: clamp(1.9rem, 8vw, 2.6rem);
}

/* The press: the signature moment when a card is finished. */
.gcard.is-pressing {
  animation: press 900ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.gcard.is-pressing .gcard__names,
.gcard.is-pressing .gcard__expecting,
.gcard.is-pressing .gcard__due {
  animation: ink 900ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
/* Watercolour bloom: the paint spreads from its centre like a wet wash. */
@property --bloom {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 100%;
}
.gcard.is-pressing .gcard__charm,
.is-blooming {
  animation: bloom 1100ms 380ms cubic-bezier(0.16, 1, 0.3, 1) both;
  mask-image: radial-gradient(circle at 50% 50%, #000 var(--bloom), transparent calc(var(--bloom) + 18%));
}

@keyframes press {
  0% { transform: rotate(var(--tilt)) scale(1); }
  30% { transform: rotate(0deg) scale(0.965); box-shadow: 0 1px 1px oklch(0 0 0 / 0.2); }
  100% { transform: rotate(var(--tilt)) scale(1); }
}
/* The ink lands as the press lifts. */
@keyframes ink {
  0%, 25% { opacity: 0.35; filter: blur(2px); }
  100% { opacity: 1; filter: none; }
}
@keyframes bloom {
  0% { --bloom: 0%; opacity: 0.4; filter: saturate(0.6); }
  100% { --bloom: 100%; opacity: 1; filter: none; }
}

/* ---------------------------------------------------------------- seals (item state) */

.seal {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
}
.seal svg {
  width: 100%;
  height: 100%;
}
.disc__fill {
  fill: var(--nl-paint);
}
.disc__check {
  fill: none;
  stroke: var(--nl-on-action);
  stroke-width: 9;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.disc__ring {
  fill: none;
  stroke: var(--nl-stock-edge);
  stroke-width: 5;
  stroke-dasharray: 8 7;
}

.seal--needed {
  border: 1.5px dashed var(--nl-stock-edge);
  width: 34px;
  height: 34px;
}
.seal--have .art {
  width: 100%;
}

/* On the guest page claimed rows recede: the open items and their action lead. */
.state--quiet .seal {
  width: 24px;
  height: 24px;
}

.state {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--nl-ink-soft);
  text-align: right;
}

/* ---------------------------------------------------------------- card box with tab dividers */

.box {
  position: relative;
}

.tabs {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 0 16px;
  margin: 0 -16px;
  scroll-padding-inline: 16px;
  mask-image: linear-gradient(to right, #000 calc(100% - 40px), transparent);
}
.tabs.is-scrolled-end {
  mask-image: none;
}
.tabs::-webkit-scrollbar {
  display: none;
}

.tab {
  flex: none;
  font: 600 0.9rem/1 var(--nl-font-body);
  padding: 13px 16px 12px;
  min-height: 44px;
  border: 0;
  border-radius: 12px 12px 0 0;
  background: var(--nl-stock-sunk);
  color: var(--nl-ink-soft);
  cursor: pointer;
}
.tab[aria-selected='true'] {
  background: var(--nl-stock-lift);
  color: var(--nl-ink);
  box-shadow: inset 0 3px 0 var(--nl-ink);
}
.tab__count {
  font-variant-numeric: tabular-nums;
  margin-left: 6px;
  font-weight: 500;
}

.box__panel {
  background: var(--nl-stock-lift);
  border-radius: 0 14px 14px 14px;
  box-shadow: var(--nl-card-shadow);
}

.rows {
  list-style: none;
  margin: 0;
  padding: 4px 0;
}

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 14px;
  padding: 14px 18px;
  min-height: 64px;
}
.row + .row {
  box-shadow: var(--nl-rule);
}

.row__main {
  display: grid;
  gap: 2px;
  min-width: 0;
}
/* The name column starts at 8rem and grows, so a long name wraps inside
   its column before the state or button drops to a line of its own. */
.row > .row__main,
.row > .row__with-photo {
  flex: 1 1 8rem;
}
.row__name {
  font-weight: 600;
  overflow-wrap: anywhere;
}
.row__meta {
  font-size: 0.86rem;
  color: var(--nl-ink-soft);
  font-variant-numeric: tabular-nums;
}
.row__by {
  font-size: 0.86rem;
  color: var(--nl-ink-soft);
  font-weight: 500;
  font-style: italic;
}
.row--done .row__name {
  color: var(--nl-ink-soft);
}

.group-title {
  font-size: 1.25rem;
  margin: 0 0 10px 4px;
}

/* ---------------------------------------------------------------- reply card (guest claim) */

/* The reply card: a small card torn off along the perforation, filled in, sent back. */
.reply {
  position: relative;
  margin: 2px 12px 16px;
  padding: 22px 18px 18px;
  border-radius: 2px 2px 6px 6px;
  background-color: var(--nl-stock);
  box-shadow: var(--nl-card-shadow);
  transform: rotate(-0.6deg);
  display: grid;
  gap: 14px;
  transform-origin: top center;
  animation: unfold 380ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.reply::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  border-top: 2px dashed var(--nl-stock-edge);
}
.reply__title {
  font-family: var(--nl-font-display);
  font-size: 1.2rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}
.reply__note {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  font-size: 0.86rem;
  color: var(--nl-ink-soft);
}
.reply__note veneer-icon {
  flex: none;
  margin-top: 2px;
}
.reply__actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  flex-wrap: wrap;
}

.thanks {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 4px 10px 12px;
  padding: 14px 16px;
  border-radius: 8px;
  background: var(--nl-stock);
  box-shadow: inset 0 0 0 1px var(--nl-stock-edge);
}
.thanks__heart {
  flex: none;
  width: 52px;
}
.thanks__text {
  display: grid;
  gap: 2px;
  font-size: 0.9rem;
}
.thanks__text strong {
  font-family: var(--nl-font-display);
  font-size: 1.05rem;
  font-weight: 600;
}
.thanks__undo {
  margin-left: auto;
  font: 600 0.86rem/1 var(--nl-font-body);
  background: none;
  border: 0;
  color: var(--nl-ink-soft);
  text-decoration: underline;
  text-decoration-color: var(--nl-ink-soft);
  text-underline-offset: 4px;
  cursor: pointer;
  min-height: 44px;
  padding: 0 4px;
}

@keyframes unfold {
  from { opacity: 0; transform: translateY(-8px) rotate(0deg) scaleY(0.96); }
  to { opacity: 1; transform: rotate(-0.6deg); }
}

/* ---------------------------------------------------------------- products (app voice)
 * Product photos are photography, so they belong to the app, not the card:
 * small rounded squares in list rows, never a shop-style grid. */

.product__photo {
  flex: none;
  width: 72px;
  height: 72px;
  border-radius: 10px;
  object-fit: cover;
  background: var(--nl-stock-sunk);
}
.row .product__photo {
  width: 52px;
  height: 52px;
  border-radius: 8px;
}
.row__with-photo {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  /* On very narrow screens the action wraps below the name instead of
     pushing the row past the edge. */
  flex: 1 1 160px;
}

.products {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
.product {
  background: var(--nl-stock-lift);
  border-radius: 14px;
  padding: 12px;
}
.product__row {
  display: flex;
  align-items: center;
  gap: 14px;
}
.product__main {
  display: grid;
  gap: 2px;
  min-width: 0;
  flex: 1;
}
.product__name {
  font-weight: 600;
  overflow-wrap: anywhere;
}
.product__meta {
  font-size: 0.86rem;
  color: var(--nl-ink-soft);
}
.product__shops {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  text-align: start;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--nl-ink);
  font: 500 0.86rem/1.2 var(--nl-font-body);
  text-decoration: underline;
  text-decoration-color: var(--nl-stock-edge);
  text-underline-offset: 3px;
  cursor: pointer;
}
.product__shops[aria-expanded='true'] veneer-icon {
  transform: rotate(180deg);
}
.product__added {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--nl-ink-soft);
}

.offers {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
}
.offer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 10px 4px;
  font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
}
.offer + .offer {
  box-shadow: var(--nl-rule);
}
.offer__shop {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.offer__price {
  font-weight: 600;
}

/* Affiliate partners are labelled where the link is, in plain words. */
.partner {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--nl-stock-sunk);
  color: var(--nl-ink-soft);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  width: fit-content;
}

.disclosure {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  font-size: 0.84rem;
  color: var(--nl-ink-soft);
  max-width: 62ch;
}
.disclosure veneer-icon {
  flex: none;
  margin-top: 2px;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(18px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  width: min(calc(100% - 32px), 460px);
  padding: 10px 10px 10px 16px;
  border-radius: 12px;
  background: var(--nl-ink);
  color: var(--nl-stock-lift);
  font-weight: 500;
  box-shadow: var(--nl-card-shadow);
}
.toast__undo {
  margin-left: auto;
  min-height: 40px;
  padding: 0 12px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: inherit;
  font: 600 0.9rem/1 var(--nl-font-body);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

/* ---------------------------------------------------------------- choice cards (onboarding) */

.choices {
  display: grid;
  gap: 10px;
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}
.choices legend {
  font-weight: 600;
  margin-bottom: 10px;
  padding: 0;
}
.choices--two {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.choice {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 12px 16px;
  border-radius: 10px;
  background: var(--nl-stock-lift);
  box-shadow: inset 0 0 0 1.5px var(--nl-stock-edge);
  cursor: pointer;
  font-weight: 600;
  transition: box-shadow 160ms ease-out, transform 160ms ease-out;
}
body.on-table .choice {
  background: light-dark(color-mix(in oklch, var(--nl-table) 60%, white), color-mix(in oklch, var(--nl-table-ink) 9%, var(--nl-table)));
  box-shadow: inset 0 0 0 1.5px color-mix(in oklch, var(--nl-table-ink) 18%, transparent);
}
.choice input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
/* Inside a reply card (the guest's "where are you with it?"): two side by
   side where they fit, a touch smaller than the onboarding choices. */
.choices--compact {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));
  gap: 8px;
}
.choices--compact legend {
  grid-column: 1 / -1;
}
.choice--compact {
  min-height: 48px;
  padding: 10px 14px;
  font-weight: 500;
}

.choice:has(input:checked) {
  box-shadow: inset 0 0 0 2px var(--nl-ink), var(--nl-card-shadow);
}
body.on-table .choice:has(input:checked) {
  box-shadow: inset 0 0 0 2px var(--nl-table-ink), 0 6px 16px -8px oklch(0 0 0 / 0.3);
}
.choice:has(input:focus-visible) {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}
.choice:active {
  transform: scale(0.985);
}
.choice__mark {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px currentColor;
  display: grid;
  place-items: center;
  opacity: 0.5;
}
.choice:has(input:checked) .choice__mark {
  opacity: 1;
  box-shadow: inset 0 0 0 7px currentColor;
}
.choice__sub {
  display: block;
  font-weight: 400;
  font-size: 0.86rem;
  opacity: 0.75;
}

/* Stock swatches: five little cards on the table. */
.stocks {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
  border: 0;
  margin: 0;
  padding: 0;
}
.stock {
  display: grid;
  justify-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 0.82rem;
  font-weight: 600;
}
.stock input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.stock__swatch {
  width: 100%;
  aspect-ratio: 5 / 7;
  border-radius: 5px;
  background: var(--nl-card);
  box-shadow: var(--nl-card-shadow);
  transform: rotate(var(--r, 0deg));
  transition: transform 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
.stock:has(input:checked) .stock__swatch {
  transform: translateY(-6px) rotate(0deg);
  box-shadow: 0 0 0 2px var(--nl-table-ink), var(--nl-card-shadow);
}
.stock:has(input:focus-visible) .stock__swatch {
  outline: 2px solid var(--nl-table-ink);
  outline-offset: 4px;
}

/* Toggle chips for "what we already have". */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 8px 14px;
  border-radius: 999px;
  border: 0;
  font: 600 0.9rem/1 var(--nl-font-body);
  background: light-dark(color-mix(in oklch, var(--nl-table) 60%, white), color-mix(in oklch, var(--nl-table-ink) 9%, var(--nl-table)));
  color: inherit;
  box-shadow: inset 0 0 0 1.5px color-mix(in oklch, var(--nl-table-ink) 18%, transparent);
  cursor: pointer;
}
body:not(.on-table) .chip {
  background: var(--nl-stock-lift);
  box-shadow: inset 0 0 0 1.5px var(--nl-stock-edge);
}
.chip[aria-pressed='true'] {
  box-shadow: inset 0 0 0 2px currentColor;
}
.chip__dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px currentColor;
  opacity: 0.45;
  display: grid;
  place-items: center;
}
.chip[aria-pressed='true'] .chip__dot {
  opacity: 1;
  background: currentColor;
  box-shadow: none;
}
.chip[aria-pressed='true'] .chip__dot veneer-icon {
  color: var(--nl-table);
}
body:not(.on-table) .chip[aria-pressed='true'] .chip__dot veneer-icon {
  color: var(--nl-stock-lift);
}
.chip__dot svg {
  width: 12px;
  height: 12px;
}

/* A Veneer button stretches when its container makes it a block. */
.is-block::part(button) {
  width: 100%;
}

/* The flat paper button. Colour, radius and size come from tokens (the action
 * colour is calculated in nidodo.css); the part only adds what no token
 * covers: one small shared paper tile (CC0 scan, centred on 50% grey), laid
 * over the fill with soft-light so the colour itself does not shift. */
[data-veneer-theme='nidodo'] veneer-button::part(button) {
  background-image: url('../../vendor/textures/paper-grain-tile.webp');
  background-size: 512px 300px;
  background-blend-mode: soft-light;
}
/* The one thing to do on a page reads as such: a firmer label. */
[data-veneer-theme='nidodo'] veneer-button[variant='primary']::part(button) {
  font-weight: 650;
}
[data-veneer-theme='nidodo'] veneer-button[variant='ghost']::part(button) {
  background-image: none;
}
/* Secondary: a lighter sheet of the same stock beside the primary. Veneer's
 * own fill is 6% black, which the grain turned into grey noise. */
[data-veneer-theme='nidodo'] veneer-button[variant='secondary']::part(button) {
  background-color: var(--nl-stock-lift);
  box-shadow: inset 0 0 0 1px var(--nl-stock-edge);
}
/* veneer-button draws its focus ring in --vnr-color-accent, which here is the
 * button's own fill. No token covers it, so the part sets an ink ring
 * (upstream note in the backlog: read --vnr-color-focus-ring instead). */
[data-veneer-theme='nidodo'] veneer-button::part(button):focus-visible {
  outline: 2px solid var(--nl-ink);
  outline-offset: 3px;
}
/* High contrast and forced colours: the texture steps aside, the shape stays. */
@media (prefers-contrast: more), (forced-colors: active) {
  [data-veneer-theme='nidodo'] veneer-button::part(button) {
    background-image: none;
  }
}

/* ---------------------------------------------------------------- contrast and forced colours
 * Boundaries and selections are drawn with shadows and fills elsewhere; here
 * they get real borders and system colours so nothing depends on them. */

@media (prefers-contrast: more) {
  [data-veneer-theme='nidodo'],
  [data-veneer-theme='nidodo'] [data-stock] {
    --nl-ink-soft: var(--nl-ink);
    --nl-stock-edge: var(--nl-ink-soft);
  }
  .choice,
  .chip,
  .tab,
  .modes__tab {
    border: 1.5px solid var(--nl-ink);
  }
}

@media (forced-colors: active) {
  .choice,
  .chip,
  .tab,
  .modes__tab,
  .stock__swatch,
  .gcard,
  .reply,
  .product,
  .box__panel {
    border: 1px solid CanvasText;
  }
  .choice:has(input:checked),
  .chip[aria-pressed='true'],
  .chip--radio:has(input:checked),
  .tab[aria-selected='true'],
  .modes__tab[aria-selected='true'],
  .stock:has(input:checked) .stock__swatch {
    border: 3px solid Highlight;
  }
  .choice:has(input:checked) .choice__mark {
    background: Highlight;
  }
  .onb__progress i.is-on {
    background: Highlight;
    opacity: 1;
  }
  /* Fixed bars lose their fade in forced colours; give them a solid ground. */
  .onb__actions,
  .dock {
    background: Canvas;
    border-top: 1px solid CanvasText;
  }
}

/* ---------------------------------------------------------------- reduced motion */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
  }
}

/* Light or dark: the same quiet line as the language, right under it; the
   chosen one reads like the current language (plain, heavier). */
.themeline.page__lang,
.themeline.onb__lang {
  margin-top: -6px;
}
.langline button[aria-pressed='true'] {
  color: var(--nl-ink);
  font-weight: 650;
  cursor: default;
}
