/* ═══════════════════════════════════════════════════════════════════════════
   GRAMS — high-protein dinners.

   THE ONE IDEA: the number is the picture.

   This app has no food photography, and that is a decision rather than a gap.
   The keyless image sources that are actually available (Openverse, Wikimedia
   Commons) return banquet halls, plastic deli tubs and flash-lit plates on
   formica; every plant protein — tofu, lentils, yoghurt, beans — exists only as
   supermarket packaging. A recipe app that leans on photography it cannot get
   is a worse app than one built around the thing it does have, which here is
   twenty-four honest sets of numbers.

   So the LIBRARY ROW IS THE BAR. Each row is tinted from the left in
   proportion to what one serving does to your day, and the ragged right edge
   down the list is a chart you read by scrolling. No separate graph, no
   furniture, nothing decorative — the data is the image.

   TYPE — two families, four files.
     Kalice   dish names, the big figures, the day's total
     Selecta  everything measured, labelled or counted. tabular, always.

   COLOUR — paper, ink, one pine green. The green is spent on the measure and
   on the one action; nothing else in the app is coloured.
   ═══════════════════════════════════════════════════════════════════════════ */

@font-face { font-family: Selecta; src: url('fonts/Selecta-Regular.otf') format('opentype'); font-weight: 400; font-display: block; }
@font-face { font-family: Selecta; src: url('fonts/Selecta-Medium.otf')  format('opentype'); font-weight: 500; font-display: block; }
@font-face { font-family: Selecta; src: url('fonts/Selecta-Bold.otf')    format('opentype'); font-weight: 700; font-display: block; }
@font-face { font-family: Kalice;  src: url('fonts/Kalice-Regular.woff2') format('woff2');   font-weight: 400; font-display: block; }

:root {
  --paper: #FBFAF8;
  --raised: #FFFFFF;
  --pressed: #F1EEE9;

  /* every ink is measured against --paper; --ink-3 is the lightest that still
     holds 4.5:1, and it is the last one allowed to carry words */
  --ink-1: #17141A;          /* 17.6:1 */
  --ink-2: #57515A;          /* 7.2:1  */
  --ink-3: #756F78;          /* 4.6:1  */
  --ink-4: #B6B0B8;          /* rule and glyph only, never text */

  --pine: #20574A;           /* 8.5:1 — the measure, and the one action */
  /* The wash has to survive being 13% of itself over warm paper. At .085 and
     again at .13 it composited to a neutral grey — the eye reads the lightness
     and throws the hue away. .2 of a more saturated pine lands on #CADCD5,
     which is unmistakably green and still sits a long way under the type. */
  --pine-wash: rgba(16, 118, 92, .20);
  --pine-press: #164036;

  --hair: rgba(23, 20, 26, .085);
  --hair-2: rgba(23, 20, 26, .15);

  /* eight steps, nothing off the list */
  --t-1: 11px;   /* caps labels, units, tabs */
  --t-2: 13px;   /* meta, quantities */
  --t-3: 15px;   /* body, steps, rows */
  --t-4: 19px;   /* dish name in a list */
  --t-5: 27px;   /* the row figure */
  --t-6: 38px;   /* screen titles, dish name */
  --t-7: 62px;   /* the day's total */

  --pad: 20px;
  --tabh: 56px;
  --e: cubic-bezier(.22, .68, .16, 1);
  --st: 240ms;
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
}

* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; overflow: hidden; }
body {
  background: var(--paper); color: var(--ink-1);
  font: 400 var(--t-3)/1.45 Selecta, ui-sans-serif, system-ui, sans-serif;
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; text-align: left; }
button:focus { outline: none; }
button:focus-visible { outline: 2px solid var(--pine); outline-offset: -2px; }

.app { position: relative; width: 100%; height: 100dvh; overflow: hidden; background: var(--paper); }
.stage { position: absolute; inset: 0; }
.screen {
  position: absolute; inset: 0; display: none;
  overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; scrollbar-width: none;
}
.screen::-webkit-scrollbar { display: none; }
.screen[data-on] { display: block; }

.pad { padding-left: var(--pad); padding-right: var(--pad); }
.cap { font: 500 var(--t-1)/1.2 Selecta; letter-spacing: .11em; text-transform: uppercase; color: var(--ink-3); }
.serif { font-family: Kalice, Georgia, serif; font-weight: 400; letter-spacing: -.02em; }

/* ── the head of a screen ─────────────────────────────────────────────────── */
.head { padding: calc(var(--sat) + 26px) var(--pad) 0; }
.head h1 { font: 400 var(--t-6)/1.06 Kalice, Georgia, serif; letter-spacing: -.025em; }
.head .sub { margin-top: 9px; font-size: var(--t-2); color: var(--ink-3); }

/* ═══ SCREEN: library ═══════════════════════════════════════════════════════
   A feed of photographs, one to a row, each carrying its own gram figure. The
   photograph is a SQUARE INSET rather than a full bleed: the source is 700px,
   and a full-bleed hero on a 393pt phone would be asking 786px of it. Inset at
   the content width it lands at 1:1 and stays sharp — and a plate with paper
   around it suits an app about measuring plates better than a backdrop does.

   The bar under each card is still the chart, and still shows whatever the list
   is sorted by. */
.lib { padding-bottom: calc(var(--tabh) + var(--sab) + 34px); }

.sortbar { display: flex; gap: 6px; padding: 22px var(--pad) 4px; }
.sortbar button {
  min-height: 34px; padding: 0 13px; border-radius: 999px;
  border: 1px solid var(--hair-2); color: var(--ink-2);
  font: 500 var(--t-1)/1 Selecta; letter-spacing: .09em; text-transform: uppercase;
  display: inline-flex; align-items: center;
  transition: background-color var(--st) var(--e), color var(--st) var(--e), border-color var(--st) var(--e);
}
.sortbar button[data-sel] { background: var(--ink-1); color: var(--paper); border-color: var(--ink-1); }

.feed { padding: 20px var(--pad) 0; display: flex; flex-direction: column; gap: 34px; }

.card { display: block; width: 100%; text-align: left; }
.card:active .ph img { transform: scale(1.012); }

.ph {
  position: relative; display: block; width: 100%; aspect-ratio: 1 / 1;
  border-radius: 5px; overflow: hidden; background: var(--pressed);
  box-shadow: 0 14px 26px -16px rgba(48, 38, 32, .34), 0 0 0 1px var(--hair);
}
.ph img { width: 100%; height: 100%; object-fit: cover; display: block;
          transition: transform 420ms var(--e); }
/* the figure sits ON the food, so it needs its own ground rather than luck */
.ph-scrim { position: absolute; left: 0; right: 0; bottom: 0; height: 46%; pointer-events: none;
  background: linear-gradient(to top, rgba(12, 14, 13, .62), rgba(12, 14, 13, .28) 42%, rgba(12, 14, 13, 0)); }
.ph-g {
  position: absolute; left: 16px; bottom: 13px; color: #fff;
  font: 500 40px/1 Selecta; letter-spacing: -.035em;
  text-shadow: 0 1px 14px rgba(0, 0, 0, .45);
}
.ph-g i { font-style: normal; font-size: var(--t-3); letter-spacing: 0; margin-left: 3px; opacity: .82; }
.ph-in {
  position: absolute; right: 12px; top: 12px;
  background: var(--pine); color: #fff; border-radius: 999px; padding: 6px 11px;
  font: 500 var(--t-1)/1 Selecta; letter-spacing: .09em; text-transform: uppercase;
}

.c-name { display: block; margin-top: 14px;
  font: 400 23px/1.18 Kalice, Georgia, serif; letter-spacing: -.02em; color: var(--ink-1); }
.c-meta { display: block; margin-top: 7px; font-size: var(--t-2); color: var(--ink-3);
          white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.c-meta span { margin: 0 5px; color: var(--ink-4); }
.c-meta b { font-weight: 400; color: var(--ink-2); }
.c-bar { display: block; margin-top: 12px; height: 3px; background: #E7E2DC; border-radius: 2px; }
.c-bar i { display: block; height: 100%; border-radius: 2px; background: var(--pine);
           width: calc(var(--fill, 0) * 100%); }

/* ═══ SCREEN: dish ══════════════════════════════════════════════════════════ */
.dish { padding-bottom: calc(var(--tabh) + var(--sab) + 34px); }
.dish-top { padding: calc(var(--sat) + 18px) var(--pad) 0; }
.back {
  min-height: 44px; display: inline-flex; align-items: center; gap: 7px;
  font: 500 var(--t-1)/1 Selecta; letter-spacing: .11em; text-transform: uppercase; color: var(--ink-3);
  margin-left: -4px; padding: 0 4px;
}
.back svg { width: 13px; height: 13px; }
.hero { position: relative; margin-top: 10px; border-radius: 5px; overflow: hidden;
        aspect-ratio: 1 / 1; background: var(--pressed);
        box-shadow: 0 18px 34px -18px rgba(48, 38, 32, .38), 0 0 0 1px var(--hair); }
.hero img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 44%;
  background: linear-gradient(to top, rgba(12, 14, 13, .66), rgba(12, 14, 13, .28) 44%, rgba(12, 14, 13, 0)); }
.hero-g { position: absolute; z-index: 1; left: 18px; bottom: 15px; color: #fff;
          font: 500 56px/1 Selecta; letter-spacing: -.04em; text-shadow: 0 1px 16px rgba(0,0,0,.45); }
.hero-g i { font-style: normal; font-size: 21px; letter-spacing: 0; margin-left: 3px; opacity: .84; }
.hero-g em { display: block; margin-top: 6px; font-style: normal;
             font: 500 var(--t-1)/1 Selecta; letter-spacing: .12em; text-transform: uppercase; opacity: .8; }

.dish h1 { margin-top: 18px; font: 400 var(--t-6)/1.08 Kalice, Georgia, serif; letter-spacing: -.028em; }
.dish .line {
  margin-top: 13px; font: 400 var(--t-4)/1.34 Kalice, Georgia, serif;
  letter-spacing: -.015em; color: var(--ink-2); max-width: 30ch;
}
.dish .by { margin-top: 14px; }

/* the figure block — protein is the hero, the rest are its context */
.figs { display: flex; align-items: flex-end; gap: 0; margin: 26px var(--pad) 0;
        border-top: 1px solid var(--ink-1); border-bottom: 1px solid var(--hair); }
.fig { flex: 1; padding: 13px 0 12px; }
.fig + .fig { border-left: 1px solid var(--hair); padding-left: 12px; }
.fig b { display: block; font: 500 var(--t-4)/1 Selecta; letter-spacing: -.02em; color: var(--ink-1); }
.fig i { display: block; margin-top: 6px; font-style: normal; font: 500 var(--t-1)/1 Selecta;
         letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.fig-hero { flex: 1.5; }
.fig-hero b { font-size: 42px; letter-spacing: -.035em; color: var(--pine); }
.fig-hero b span { font-size: var(--t-3); letter-spacing: 0; color: var(--ink-3); margin-left: 3px; }

/* what one serving does to the day */
.share { margin: 16px var(--pad) 0; }
.share-bar { height: 6px; background: var(--pressed); border-radius: 3px; overflow: hidden; }
.share-bar i { display: block; height: 100%; background: var(--pine); border-radius: 3px;
               width: calc(var(--fill, 0) * 100%); transition: width var(--st) var(--e); }
.share p { margin-top: 9px; font-size: var(--t-2); color: var(--ink-3); }
.share p b { font-weight: 400; color: var(--ink-1); }

/* serves */
.serves { display: flex; align-items: center; justify-content: space-between;
          margin: 26px var(--pad) 0; padding-top: 17px; border-top: 1px solid var(--hair); }
.serves-l b { display: block; font: 500 var(--t-3)/1.2 Selecta; }
.serves-l i { display: block; margin-top: 3px; font-style: normal; font-size: var(--t-2); color: var(--ink-3); }
.step2 { display: flex; align-items: center; border: 1px solid var(--hair-2); border-radius: 3px; }
.step2 button { width: 46px; height: 46px; display: grid; place-items: center; color: var(--ink-1); }
.step2 button:disabled { color: var(--ink-4); }
.step2 button:active:not(:disabled) { background: var(--pressed); }
.step2 output { width: 44px; text-align: center; font: 500 var(--t-3)/1 Selecta;
                border-left: 1px solid var(--hair); border-right: 1px solid var(--hair); padding: 15px 0; }
.step2 svg { width: 13px; height: 13px; }

/* ingredients — each line carries a hairline showing how much of the dish's
   protein arrives with it. This is the only place in any recipe app where you
   can see that the yoghurt is doing more work than the chicken skin. */
.sect { margin: 30px var(--pad) 0; }
.sect-head { display: flex; align-items: baseline; justify-content: space-between;
             padding-bottom: 11px; border-bottom: 1px solid var(--hair-2); }
.ing { display: block; width: 100%; padding: 11px 0 10px; border-bottom: 1px solid var(--hair); }
.ing-top { display: flex; align-items: baseline; gap: 12px; }
.ing-note { margin-top: 13px; font-size: var(--t-2); color: var(--ink-3); }
.ing-n { flex: 1; min-width: 0; font-size: var(--t-3); color: var(--ink-1); }
.ing-q { flex: none; font: 500 var(--t-2)/1 Selecta; color: var(--ink-2); }
/* display:block is load-bearing — this is a <span>, and height on an inline
   box is simply ignored, so the whole protein-per-ingredient idea rendered as
   nothing at all and looked like a design that had never had it. */
.ing-bar { display: block; margin-top: 8px; height: 3px; background: #E7E2DC; border-radius: 2px; }
.ing-bar i { display: block; height: 100%; border-radius: 2px; background: var(--ink-4); width: calc(var(--p, 0) * 100%); }
.ing[data-lead] .ing-n { color: var(--ink-1); }
.ing[data-lead] .ing-bar i { background: var(--pine); }
.hold { margin-top: 13px; font-size: var(--t-2); color: var(--ink-3); }

/* method */
.stp { display: flex; gap: 15px; padding: 15px 0; border-bottom: 1px solid var(--hair); }
.stp-n { flex: none; width: 22px; font: 500 var(--t-2)/1.5 Selecta; color: var(--ink-4); }
.stp-t { flex: 1; font-size: var(--t-3); line-height: 1.52; color: var(--ink-1); }

.act { margin: 30px var(--pad) 0; }
.btn {
  width: 100%; min-height: 54px; display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  border-radius: 3px; font: 500 var(--t-3)/1 Selecta;
  transition: background-color var(--st) var(--e), transform 150ms var(--e);
}
.btn:active { transform: scale(.987); }
.btn-go { background: var(--pine); color: #fff; }
.btn-go:active { background: var(--pine-press); }
.btn-out { border: 1px solid var(--hair-2); color: var(--ink-1); }
.btn-out:active { background: var(--pressed); }
.btn svg { width: 14px; height: 14px; }

/* ═══ SCREEN: today ═════════════════════════════════════════════════════════ */
.today { padding-bottom: calc(var(--tabh) + var(--sab) + 30px); }

.day { padding: calc(var(--sat) + 26px) var(--pad) 0; }
.day-fig { display: flex; align-items: baseline; gap: 10px; }
.day-fig b { font: 400 var(--t-7)/.92 Kalice, Georgia, serif; letter-spacing: -.035em; }
.day-fig .of { font: 400 var(--t-4)/1 Kalice, Georgia, serif; color: var(--ink-3); letter-spacing: -.02em; }
.day-fig .unit { font: 500 var(--t-2)/1 Selecta; color: var(--ink-3); letter-spacing: .05em; text-transform: uppercase; }

/* the day's measure, segmented — one block per dish, in the order you added
   them, so the bar is a record and not just a percentage */
.meter { display: flex; gap: 2px; margin-top: 20px; height: 10px;
         background: var(--pressed); border-radius: 5px; overflow: hidden; }
.meter i { display: block; height: 100%; background: var(--pine); }
.meter i:nth-child(even) { background: #2E6E5E; }   /* one step apart, so the joins read */
/* Reaching the target is the good outcome, so it does not turn the meter black
   — black read as a warning. It deepens instead, and the copy above does the
   announcing. */
.meter[data-over] i { background: var(--pine-press); }
.meter[data-over] i:nth-child(even) { background: #1E5245; }

.day-note { margin-top: 13px; font-size: var(--t-2); color: var(--ink-3); }
.day-note b { font-weight: 400; color: var(--ink-1); }

/* the target, adjustable in place — the app's only setting, and it does not
   get a screen of its own */
.target { display: flex; align-items: center; justify-content: space-between;
          margin: 24px var(--pad) 0; padding-top: 16px; border-top: 1px solid var(--hair); }

/* what you added */
.eaten { margin: 26px var(--pad) 0; }
.eat {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 12px 0; border-bottom: 1px solid var(--hair);
}
.eat-ph { flex: none; width: 60px; height: 60px; border-radius: 4px; object-fit: cover;
          box-shadow: 0 0 0 1px var(--hair); }
.eat-t { flex: 1; min-width: 0; }
.eat-n { display: block; font: 400 var(--t-4)/1.18 Kalice, Georgia, serif; letter-spacing: -.015em; }
.eat-g { display: block; margin-top: 4px; font-size: var(--t-2); color: var(--ink-3); }
/* The glyph wants to be small; the thumb does not care what the glyph wants.
   44x44 of hit area, pulled back out of the layout with negative margin so the
   row keeps the height it was designed to have. */
.eat-x { flex: none; width: 44px; height: 44px; margin: -11px -13px -11px 0; display: grid; place-items: center; color: var(--ink-4); }
.eat-x svg { width: 12px; height: 12px; }
.eat-x:active { color: var(--ink-1); }

/* ── the empty state ──────────────────────────────────────────────────────
   An empty screen that apologises is a wasted screen. This one does the work
   instead: it shows the day at zero and then proposes a way to fill it, with
   the arithmetic already done and one button that takes it. */
.propose { margin: 30px var(--pad) 0; padding-top: 22px; border-top: 1px solid var(--ink-1); }
.propose h2 { font: 400 var(--t-4)/1.3 Kalice, Georgia, serif; letter-spacing: -.015em; max-width: 26ch; }
.propose .why { margin-top: 8px; font-size: var(--t-2); color: var(--ink-3); }
.plan { margin-top: 18px; }
.plan-i { display: flex; align-items: center; gap: 14px; padding: 11px 0; border-bottom: 1px solid var(--hair); }
.plan-ph { flex: none; width: 56px; height: 56px; border-radius: 4px; object-fit: cover;
           box-shadow: 0 0 0 1px var(--hair); }
.plan-i .n { flex: 1; min-width: 0; font: 400 var(--t-4)/1.18 Kalice, Georgia, serif; letter-spacing: -.015em; }
.plan-i .n em { display: block; margin-top: 4px; font-style: normal; font-family: Selecta;
                font-size: var(--t-2); color: var(--ink-3); letter-spacing: 0; }
.plan-i .g { flex: none; font: 500 var(--t-3)/1.2 Selecta; color: var(--pine); }
.plan-sum { display: flex; align-items: baseline; justify-content: space-between; padding: 13px 0 0; }
.plan-sum b { font: 500 var(--t-3)/1 Selecta; }
.propose .acts { display: flex; gap: 9px; margin-top: 20px; }
.propose .acts .btn { flex: 1; }
.propose .acts .btn-out { flex: 0 0 auto; width: 54px; padding: 0; }

.foot { margin: 34px var(--pad) 0; padding-top: 16px; border-top: 1px solid var(--hair); }
.foot p { font-size: var(--t-2); line-height: 1.55; color: var(--ink-3); max-width: 42ch; }
.foot p + p { margin-top: 9px; }

/* ── tabs ─────────────────────────────────────────────────────────────────── */
.tabs {
  position: absolute; z-index: 4; left: 0; right: 0; bottom: 0;
  height: calc(var(--tabh) + var(--sab)); padding: 0 var(--pad) var(--sab);
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  border-top: 1px solid var(--hair);
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
}
.tab {
  min-height: 44px; display: flex; align-items: center; justify-content: center; gap: 7px;
  font: 500 var(--t-1)/1 Selecta; letter-spacing: .11em; text-transform: uppercase; color: var(--ink-3);
  position: relative; transition: color var(--st) var(--e);
}
.tab[data-sel] { color: var(--ink-1); }
.tab[data-sel]::before { content: ''; position: absolute; top: 0; left: 50%; width: 20px; height: 1px;
                         transform: translateX(-50%); background: var(--ink-1); }
.tab-n {
  font-style: normal; min-width: 17px; height: 17px; border-radius: 9px; padding: 0 5px;
  display: none; align-items: center; justify-content: center;
  background: var(--pine); color: #fff; font-size: var(--t-1); letter-spacing: 0;
}
.tab-n[data-n] { display: inline-flex; }

/* ── entrances ────────────────────────────────────────────────────────────── */
.screen[data-on] > [data-enter] { animation: rise 300ms var(--e) both; }
@keyframes rise { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 1ms !important; transition-duration: 1ms !important; } }

/* ── the desktop device frame ─────────────────────────────────────────────
   On a phone the app is the whole window. On a desktop it pins itself to a
   phone-sized rectangle inside a frame, because a 1600px-wide recipe row is
   not a design anyone is proposing. */
.device { width: 100%; height: 100%; }
.host { width: 100%; height: 100%; }
@media (min-width: 820px) and (min-height: 900px) {
  body { background: #E9E5DF; display: grid; place-items: center; }
  .device {
    width: 402px; height: 874px; border-radius: 56px; padding: 11px;
    background: linear-gradient(158deg, #6f6f75 0%, #3d3d42 26%, #55555c 52%, #2f2f34 78%, #63636a 100%);
    box-shadow: 0 0 0 1px rgba(255,255,255,.16) inset, 0 2px 3px rgba(0,0,0,.4),
                0 60px 120px -40px rgba(40,32,28,.55), 0 20px 44px -22px rgba(40,32,28,.4);
  }
  .host { border-radius: 45px; overflow: hidden; background: var(--paper); position: relative; }
  .app { height: 852px; }
}
