/* ============================================================
   Hungry — foundations
   ============================================================

   Everything visual starts here: surfaces, ink, accent, geometry,
   shadow, motion. Components below consume these and almost never
   invent their own values.

   Two ideas do most of the work.

   1. Elevation is a real scale, not one translucent white.
      Page → section → card → control → primary action. Each step is a
      distinct surface with its own hairline and its own shadow, so the
      eye can tell which layer it is looking at without being told. The
      old system used a single rgba(255,255,255,.045) for every one of
      those, which is why everything blended together.

   2. The accent is spent, not sprinkled.
      One warm colour, reserved for the primary action, the current
      state, and the match figure. Everything else is neutral and lets
      it be the loudest thing on screen. Colour used everywhere is
      colour that means nothing.
   ============================================================ */

:root {
  color-scheme: dark;

  /* ---- surfaces ------------------------------------------------
     Solid, not translucent. Stacked whites over a dark ground go
     muddy the moment two of them overlap, and they make it
     impossible to say which layer is on top.

     Every one of these carries a degree or two of warmth now — the
     greys used to sit on the blue side of neutral, which is the right
     call for a tool and the wrong one for something about dinner. It
     is deliberately below the threshold of being noticed: side by side
     you can see it, on its own it just stops feeling clinical. */
  --bg:             #0E0F15;   /* the page itself */
  --bg-elev:        #13141C;   /* a quiet band on the page */
  --surface:        #191B24;   /* a card */
  --surface-raised: #21232E;   /* a control sitting on a card */
  --surface-inset:  #131520;   /* a well: inputs, tracks, tables */
  --surface-glass:  rgba(25,27,36,.74);

  /* Hairlines get *fainter* as things rise, because a raised surface
     is already separated by its shadow and doesn't need an outline
     shouting as well. */
  --line:        rgba(255,255,255,.06);
  --line-strong: rgba(255,255,255,.11);
  --line-focus:  rgba(255,255,255,.22);

  /* The single highlight that makes a control feel like an object
     rather than a rectangle: one pixel of light along its top edge. */
  --sheen: inset 0 1px 0 rgba(255,255,255,.055);

  /* ---- ink ---------------------------------------------------- */
  --text:   #F2F2F5;
  /* Secondary is set a step brighter than it was. Tertiary is pinned at its
     contrast floor and cannot move, so the way to make the two tiers read as
     two tiers is to open the gap from above. */
  --text-2: #B2B2BC;
  /* Tertiary is where small-caps labels live, so it is set by contrast
     rather than by taste: any lower and the section headings fall under
     4.5:1 against the surfaces they sit on. */
  --text-3: #86868F;
  /* Nothing legible is set in this — it is for a control that is off, where
     the point is to look unavailable. */
  --text-off: #5A5A63;

  /* ---- colour, with jobs --------------------------------------

     Three colours, each with one meaning, rather than one colour doing
     everything. The app used to spend a single orange on the primary
     action, the current tab, the match figure and every selected control,
     which is a lot of weight for one hue to carry and left the interface
     reading as monochrome with an orange fringe.

       brand  — where you are and what is selected. Navigation, chosen
                filters, chosen options. It is the app's own colour and it
                never asks you to do anything.
       accent — the one thing to press. Choose This, and the equivalent
                primary action on a screen that has one.
       good   — a fact about the world: open, a strong match, saved.

     Warmth still comes from the accent and the ground, not from flooding
     the palette; the neutrals stay cool enough that nothing reads beige. */
  --brand:      #8B7BFF;
  --brand-ink:  #FFFFFF;
  --brand-text: #A79AFF;      /* brand as type, lifted for contrast */
  --brand-wash: rgba(139,123,255,.15);
  --brand-edge: rgba(139,123,255,.34);

  /* A restrained teal, for the occasional supporting signal. Used sparingly
     and never as a second brand. */
  --teal:       #4FC3DE;
  --teal-wash:  rgba(79,195,222,.13);

  --accent:      #FF7043;
  --accent-ink:  #FFFFFF;      /* text on top of the accent */
  --accent-text: #FF8A63;      /* accent as type, lifted for contrast */
  --accent-wash: rgba(255,112,67,.12);
  --accent-edge: rgba(255,112,67,.32);
  --grad: linear-gradient(180deg, #FF7C52 0%, #F4602F 100%);

  --good: #37D6A0;
  --warn: #FBBF24;
  --bad:  #FB7185;
  /* The match figure, coloured by how good the match is. Standalone type —
     a number, not a label sitting on a wash — so it carries more saturation
     than the tint colours below without shouting. Measured on the card:
     10.5:1 and 8.2:1. */
  --match-high: #4ADE9B;
  /* Pushed to a rose rather than a coral, for the same reason as light mode:
     the accent is at hue 15°, and a low match has to be unmistakably not
     that. 32° off, 7.9:1. */
  --match-low:  #FA88A8;

  /* Tints for controls that carry a meaning of their own — yes, no, and
     "this just takes you somewhere". Held deliberately faint: a wash at .05
     and a hairline at .14 are barely there on one button and unmistakable
     across a list of thirty, which is the only place the colour has to do any
     work. The type is desaturated to match and still measures above 8:1, so
     nothing was traded for the restraint. */
  --good-wash: rgba(52,211,153,.05);  --good-text: #8FD9B6; --good-edge: rgba(52,211,153,.14);
  --bad-wash:  rgba(251,113,133,.05); --bad-text:  #E9A3AE; --bad-edge:  rgba(251,113,133,.14);
  --info-wash: rgba(96,165,250,.05);  --info-text: #9EC0E8; --info-edge: rgba(96,165,250,.14);
  --book-wash: rgba(167,139,250,.05); --book-text: #BCACE4; --book-edge: rgba(167,139,250,.15);

  /* ---- geometry -----------------------------------------------
     A tight, even scale. The old one jumped 12 → 18 → 26 → 34, which
     is why nothing looked related to anything else. */
  --r-xs: 8px;
  --r-sm: 12px;
  --r-md: 16px;
  --r-lg: 22px;
  --r-xl: 28px;

  /* Spacing, on a 4px grid, so alignment happens by construction. */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 20px;
  --s-6: 24px;
  --s-7: 32px;
  --s-8: 40px;
  --pad: 20px;

  /* ---- depth --------------------------------------------------
     Neutral and layered: a tight contact shadow for the edge, a wide
     soft one for the lift. Coloured shadows read as decoration. */
  --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  /* Ordinary cards — a settings list, a stat, a restaurant — carry no shadow
     in dark mode: the surface is already two steps lighter than the page and
     a drop shadow under every one of them was elevation spent on things that
     are not elevated. Light mode keeps it, because there white-on-white has
     nothing else to separate with. Shadows are for the things that genuinely
     float: the bar, the recommendation, sheets. */
  --shadow-card: none;
  --shadow-md: 0 1px 2px rgba(0,0,0,.35), 0 6px 16px rgba(0,0,0,.30);
  --shadow-lg: 0 2px 4px rgba(0,0,0,.35), 0 18px 44px rgba(0,0,0,.48);
  --shadow-accent: 0 1px 2px rgba(0,0,0,.30), 0 8px 20px rgba(244,96,47,.26);

  /* ---- motion -------------------------------------------------
     Calm. The old spring overshot by 56%, which reads as playful
     rather than considered. This one settles. */
  --ease:   cubic-bezier(.22, .61, .36, 1);
  --spring: cubic-bezier(.34, 1.24, .64, 1);
  --t-fast: .16s;
  --t-base: .24s;
  --t-slow: .38s;

  /* ---- the bar ------------------------------------------------
     Furniture, not content, and sized for a thumb rather than for a cursor.
     It was 46 tall and 244 wide — legal targets, 46 by 44, and still fiddly
     to hit one-handed, because a target that is exactly the minimum is a
     target you have to aim at. It is 64 by four-fifths of the phone now.

     Not edge-to-edge, though. It keeps a margin either side and a full pill
     radius, so it still reads as a control resting on the page; a bar taken
     to the edges is a second navigation bar stacked on Safari's own, which is
     what makes an app look like broken chrome. The margin is the number that
     decides it, and it is one number rather than a width per phone: a fixed
     margin holds the bar at roughly the same share of every screen — 80% at
     390, 80% at 360 — where a fixed width would swing by seven points across
     the same range. */
  --tabbar-h: 64px;
  --tabbar-margin: 36px;
  --tabbar-pad: 6px;
  /* The floor a target may never go under. Nothing here is near it any more —
     the five regions come out at 55 to 61 wide by 62 tall — but it is what the
     tests measure against. */
  --touch-min: 44px;
  /* How far the bar floats above the safe area — as low as is safe, not as
     high as is comfortable, but never zero or it reads as glued to the
     browser's chrome rather than floating over the page. Four points *plus*
     the inset, never instead of it. */
  --tabbar-lift: 4px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);

  /* The two numbers everything at the bottom of the app is placed with.
     --tabbar-bottom is where the bar sits: above the home indicator when the
     content runs to the edge of the phone, above Safari's toolbar when it
     doesn't, because that is exactly what the inset reports in each case.
     --tabbar-block is the room it takes up — the bar, the air under it and the
     same air again above it — and it is the one value a page consumes to keep
     its last row reachable. Both derived, so a change to the bar's height or
     its float can't leave the clearance under it behind. */
  --tabbar-bottom: calc(var(--safe-b) + var(--tabbar-lift));
  --tabbar-block: calc(var(--tabbar-h) + var(--tabbar-lift) * 2 + var(--safe-b));

  /* The app is exactly one settled viewport tall.
     Large, not small, and the difference is the whole of why the bar used to
     move. Safari's bottom toolbar is only retracted on a page that scrolls, so
     sizing the shell to the *small* viewport — the one with that toolbar out —
     made every short screen fit exactly, scroll never, and hold the toolbar
     open, while a long screen retracted it on the first flick. The bar is
     anchored to the viewport, the viewport's bottom edge is wherever Safari's
     toolbar leaves it, and so the bar's height off the phone became a question
     of which tab you happened to open first. At the large viewport every route
     has the same answer: it settles once, to the position long screens already
     settled to, and no route change moves it again.

     lvh shipped alongside the svh the sheet is already sized with, so this
     asks nothing of a browser the app didn't ask for before. */
  --shell-h: 100lvh;

  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
          Inter, Roboto, "Helvetica Neue", system-ui, sans-serif;
}

/* In light mode the surfaces stop separating by lightness — white on
   white tells you nothing — so elevation is carried by shadow instead,
   and the hairlines do more of the work. */
html[data-theme="light"] {
  color-scheme: light;

  /* The page is a warm off-white rather than a cool grey, for the same
     reason as the dark surfaces above. Cards stay true white, so the
     warmth reads as the ground the app sits on and never as a tint over
     the content. */
  --bg:             #F7F7F5;
  --bg-elev:        #FFFFFF;
  --surface:        #FFFFFF;
  --surface-raised: #FFFFFF;
  --surface-inset:  #F2F2F0;
  --surface-glass:  rgba(255,255,255,.82);

  --line:        rgba(17,24,39,.08);
  --line-strong: rgba(17,24,39,.13);
  --line-focus:  rgba(17,24,39,.26);
  --sheen: inset 0 1px 0 rgba(255,255,255,.9);

  /* Charcoal with a trace of navy in it, rather than a warm near-black.
     It is what keeps the page from tipping into beige once the ground is
     warm and the surfaces are white. */
  --text:   #111827;
  --text-2: #5F6673;
  --text-3: #858C99;
  --text-off: #A9AFB9;

  --brand:      #6657E8;
  --brand-ink:  #FFFFFF;
  --brand-text: #5646D6;
  --brand-wash: #F1EFFF;
  --brand-edge: rgba(102,87,232,.26);

  --teal:       #12849C;
  --teal-wash:  rgba(18,132,156,.09);

  --accent:      #F0532B;
  --accent-ink:  #FFFFFF;
  --accent-text: #C9421B;
  --accent-wash: #FFF0EB;
  --accent-edge: rgba(240,83,43,.24);
  --grad: linear-gradient(180deg, #F26B33 0%, #E2531B 100%);

  --good: #159B67;
  --bad:  #DC2626;
  --match-high: #047857;   /* 5.5:1 on white */
  /* Crimson rather than brick. A plain red sits at hue 0° and the light-mode
     accent at 16°, close enough that "low" and "the usual case" read as the
     same colour at a glance; this is 30° off it, and 6.8:1. */
  --match-low:  #B01B3F;
  --good-wash: rgba(5,150,105,.045);  --good-text: #2F7A63; --good-edge: rgba(5,150,105,.13);
  --bad-wash:  rgba(220,38,38,.045);  --bad-text:  #A8534F; --bad-edge:  rgba(220,38,38,.13);
  --info-wash: rgba(37,99,235,.045);  --info-text: #44639E; --info-edge: rgba(37,99,235,.13);
  --book-wash: rgba(124,58,237,.045); --book-text: #6E5A9E; --book-edge: rgba(124,58,237,.13);

  --shadow-sm: 0 1px 2px rgba(16,18,32,.06);
  --shadow-card: 0 1px 2px rgba(16,18,32,.06);
  --shadow-md: 0 1px 2px rgba(16,18,32,.05), 0 6px 16px rgba(16,18,32,.07);
  --shadow-lg: 0 2px 6px rgba(16,18,32,.07), 0 18px 44px rgba(16,18,32,.13);
  --shadow-accent: 0 1px 2px rgba(16,18,32,.10), 0 8px 20px rgba(226,83,27,.22);
}
