/* ============================================================================
   Lazy Meal Planner — foundation stylesheet
   ----------------------------------------------------------------------------
   Tokens, reset, base elements, buttons, links, focus. Nothing page-specific.
   Load AFTER fonts.css:

     <link rel="stylesheet" href="/assets/css/fonts.css">
     <link rel="stylesheet" href="/assets/css/tokens.css">

   Palette source of truth: ../lazy-meal-planner/mobile/lib/core/theme/app_colors.dart
   Never introduce a colour that is not a token below.

   Every contrast ratio quoted in this file was computed, not estimated.
   ========================================================================== */

:root {
  /* The site is light-only. Declaring it stops browsers rendering form
     controls and scrollbars in a dark scheme against our cream ground. */
  color-scheme: light;

  /* ── Palette — raw brand colours ──────────────────────────────────────── */
  --colour-terracotta:      #C4622D;  /* AppColors.primary        */
  --colour-terracotta-dark: #A04F22;  /* AppColors.primaryDark    */
  --colour-blush:           #F0D5C4;  /* AppColors.primaryLight   */
  --colour-sage:            #6B8F5E;  /* AppColors.accent         */
  --colour-sage-dark:       #4F6B45;  /* AppColors.accentDark     */
  --colour-sage-light:      #D4E6CE;  /* AppColors.accentLight    */
  --colour-cream:           #FDF6EE;  /* AppColors.background     */
  --colour-surface:         #FFFFFF;  /* AppColors.surface        */
  --colour-surface-muted:   #F5EDE0;  /* AppColors.surfaceMuted   */
  --colour-charcoal:        #2D2015;  /* AppColors.textPrimary    */
  --colour-warm-brown:      #7A5C42;  /* AppColors.warm           */
  --colour-warm-light:      #E8D5C0;  /* AppColors.warmLight      */

  /* ── Roles — what each colour is allowed to DO ────────────────────────────
     Reach for these in page CSS, not the raw palette above. The two rules
     that matter:

       Terracotta #C4622D is DISPLAY ONLY. It is 3.82:1 on cream — fine for a
       big mark, illegal for body copy. Terracotta-dark #A04F22 is the text
       and button terracotta at 5.39:1 on cream, 5.78:1 white-on-fill.

       Sage #6B8F5E is likewise display only at 3.43:1 on cream. Sage-dark
       #4F6B45 is the readable sage at 5.56:1.
     ──────────────────────────────────────────────────────────────────────── */

  /* Grounds. Bands alternate page → page-alt → page, with at most one
     accent band per page so it stays an accent. */
  --colour-page:                  var(--colour-cream);
  --colour-page-alt:              var(--colour-surface);
  --colour-page-accent:           var(--colour-sage-light);
  --colour-footer:                var(--colour-charcoal);

  /* Cards carry NO border — tonal contrast does the work, as in the app's
     STYLE.md rule 1. A card on cream is white; a card on a white band steps
     down to muted surface instead. */
  --colour-card:                  var(--colour-surface);
  --colour-card-on-alt:           var(--colour-surface-muted);

  /* Text. Every pairing below clears 4.5:1 on cream, white and muted surface. */
  --colour-text:                  var(--colour-charcoal);    /* 14.74:1 on cream */
  --colour-text-muted:            var(--colour-warm-brown);  /*  5.70:1 on cream */
  --colour-text-accent:           var(--colour-sage-dark);   /*  5.56:1 on cream */
  --colour-text-inverse:          var(--colour-cream);       /* 14.74:1 on charcoal */
  --colour-text-inverse-muted:    var(--colour-blush);       /* 11.30:1 on charcoal */

  /* Display only — large headings and decorative marks. Never body copy. */
  --colour-display-accent:        var(--colour-terracotta);

  --colour-link:                  var(--colour-terracotta-dark); /* 5.39:1 on cream */
  --colour-link-hover:            var(--colour-charcoal);

  --colour-button-primary:        var(--colour-terracotta-dark);
  --colour-button-primary-ink:    var(--colour-surface);      /* 5.78:1 */
  --colour-button-secondary:      var(--colour-blush);
  --colour-button-secondary-ink:  var(--colour-charcoal);     /* 11.30:1 */

  /* The ring sits 2px clear of the control, so it is measured against the page
     ground: 14.74:1 on cream. Charcoal directly on the terracotta-dark button
     would be only 2.74:1, which is why the offset is not optional. */
  --colour-focus-ring:            var(--colour-charcoal);
  --colour-focus-ring-inverse:    var(--colour-cream);

  /* Hairline dividers: the header edge, the footer base, table rows, <hr>.
     Warm-light is the one tint that reads on both grounds — 11.07:1 on
     charcoal, where warm brown would be 2.59:1 and effectively invisible. */
  --colour-rule:                  var(--colour-warm-light);

  /* ── Spacing scale ───────────────────────────────────────────────────────
     4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96 / 128. Use nothing else. */
  --space-xxs:  0.25rem;   /*   4px */
  --space-xs:   0.5rem;    /*   8px */
  --space-s:    0.75rem;   /*  12px */
  --space-m:    1rem;      /*  16px */
  --space-l:    1.5rem;    /*  24px */
  --space-xl:   2rem;      /*  32px */
  --space-2xl:  3rem;      /*  48px */
  --space-3xl:  4rem;      /*  64px */
  --space-4xl:  6rem;      /*  96px */
  --space-5xl:  8rem;      /* 128px */

  /* ── Layout ──────────────────────────────────────────────────────────── */
  --container-max: 1120px;
  --gutter:        var(--space-l);   /* 24px; widens to 32px at 768px */
  --measure:       46ch;             /* ≈68 rendered characters — inside the 45–75 band.
                                        NOT 68ch: `ch` is the width of "0", which in DM Sans
                                        is 11.63px at 17px, while the average glyph in running
                                        English copy is 7.79px. The ratio is 1.49, so 66ch
                                        rendered 98 characters a line. Measured, not guessed. */
  --section-y:     var(--space-3xl); /* 64px; 96px at 768px */
  --section-y-hero: var(--space-4xl); /* 96px; 128px at 768px */

  /* ── Radii ───────────────────────────────────────────────────────────── */
  --radius-s:      8px;    /* inputs, small chips           */
  --radius-m:      12px;   /* media blocks, inline panels    */
  --radius-button: 16px;   /* matches the app's kRadiusButton */
  --radius-card:   20px;   /* matches the app's kRadiusL      */
  --radius-pill:   999px;

  /* ── Elevation ───────────────────────────────────────────────────────────
     One shadow, used sparingly. Tinted with charcoal rather than pure black so
     it stays warm against the cream ground. */
  --shadow-card: 0 2px 8px rgb(45 32 21 / 0.06);

  /* ── Type ────────────────────────────────────────────────────────────────
     clamp() carries the scale from mobile to desktop, so there are no
     type-specific media queries to keep in sync. */
  --font-display: 'DM Serif Display', Georgia, 'Times New Roman', serif;
  --font-sans:    'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --text-h1:      clamp(2.25rem, 6vw, 3.5rem);
  --text-h2:      clamp(1.75rem, 4vw, 2.5rem);
  --text-h3:      clamp(1.25rem, 2.5vw, 1.5rem);
  --text-body:    1.0625rem;   /* 17px */
  --text-small:   0.875rem;    /* 14px */
  --text-eyebrow: 0.8125rem;   /* 13px */

  --leading-h1:    1.08;
  --leading-h2:    1.18;
  --leading-h3:    1.3;
  --leading-body:  1.65;
  --leading-small: 1.5;

  --weight-regular: 400;
  --weight-medium:  500;
  --weight-bold:    700;

  --tracking-tight:   -0.01em;
  --tracking-eyebrow:  0.08em;

  /* ── Controls ────────────────────────────────────────────────────────── */
  --control-min-height: 52px;  /* 48px at 768px; never below 44px */
  --hit-target-min:     44px;  /* floor for anything tappable that is not a
                                  full-height button: nav and footer links,
                                  the brand, contents-list entries */

  /* ── Google Play badge ───────────────────────────────────────────────────
     Sizes below are the IMAGE BOX, not the badge. Google supplies the artwork
     at 646×250 with most of its required clear space already baked in as
     transparent padding — measured, exactly 41px on all four sides, so the
     badge itself is 564×168, or 67.2% of the image box. Google asks for a
     quarter of the badge height, which would be 42px, so the artwork alone is
     a pixel short of its own rule and the layout must supply the rest. It
     does, several times over: nothing sits within 19px of the badge anywhere
     it appears. The 67.2% ratio converts Google's rules into the numbers
     here:

       digital minimum badge height 28px  →  image box 41.67px  →  42px
       nav 42px → 28.2px badge     desktop nav 48px → 32.3px     hero 60px → 40.3px

     Never set a badge width. The artwork may not be rescaled non-uniformly,
     so only the height is declared and the width follows the intrinsic ratio.
     ─────────────────────────────────────────────────────────────────────── */
  --badge-height:        3.75rem;   /* 60px — hero and pricing            */
  --badge-height-nav:    2.625rem;  /* 42px — Google's smallest permitted */
  --badge-height-nav-lg: 3rem;      /* 48px — from 900px, where the header
                                       has the room for it                */

  /* ── Motion ──────────────────────────────────────────────────────────── */
  --transition-fast: 150ms ease;
}

@media (min-width: 768px) {
  :root {
    --gutter:             var(--space-xl);   /*  32px */
    --section-y:          var(--space-4xl);  /*  96px */
    --section-y-hero:     var(--space-5xl);  /* 128px */
    --control-min-height: 48px;
  }
}

/* ============================================================================
   Reset — minimal and modern
   ========================================================================== */

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

html,
body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd,
ul, ol { margin: 0; padding: 0; }

ul, ol { list-style: none; }

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

/* ============================================================================
   Base elements
   ========================================================================== */

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchor links must not land under a sticky header. */
  scroll-padding-top: var(--space-3xl);
}

body {
  background-color: var(--colour-page);
  color: var(--colour-text);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  font-weight: var(--weight-regular);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;

  /* Horizontal-scroll guard. `clip` is preferred over `hidden` because it does
     not create a scroll container, so `position: sticky` still works inside.
     `hidden` is the fallback for browsers without `clip`. */
  overflow-x: hidden;
  overflow-x: clip;
}

/* DM Serif Display has one weight and no italic. Without this, a browser will
   invent a faux-bold or faux-italic and smear the headings. */
h1, h2, h3, h4, h5, h6 {
  font-synthesis: none;
  font-synthesis-weight: none;
  text-wrap: balance;   /* stops a lone orphaned word on the last heading line */
}

h1, h2 {
  font-family: var(--font-display);
  font-weight: var(--weight-regular);   /* the only weight this face has */
  letter-spacing: var(--tracking-tight);
  color: var(--colour-text);
}

h1 { font-size: var(--text-h1); line-height: var(--leading-h1); }
h2 { font-size: var(--text-h2); line-height: var(--leading-h2); }

/* h3 and below are DM Sans — a serif at these sizes reads as a mistake. */
h3, h4, h5, h6 {
  font-family: var(--font-sans);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-h3);
  color: var(--colour-text);
}

h3 { font-size: var(--text-h3); }
h4 { font-size: var(--text-body); }
h5, h6 { font-size: var(--text-small); }

p {
  max-width: var(--measure);
  text-wrap: pretty;
}

/* Vertical rhythm between stacked flow content. Using a sibling selector means
   the last item in a block never leaves a trailing gap to hunt down. */
p + p,
p + ul,
p + ol,
ul + p,
ol + p { margin-top: var(--space-m); }

h1 + p,
h2 + p,
h3 + p { margin-top: var(--space-m); }

p + h2,
ul + h2,
ol + h2 { margin-top: var(--space-2xl); }

p + h3,
ul + h3,
ol + h3 { margin-top: var(--space-xl); }

/* Content lists opt back in to markers; navigation and card lists stay bare. */
.prose ul,
.prose ol {
  max-width: var(--measure);
  padding-left: var(--space-l);
}

.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li + li { margin-top: var(--space-xs); }
.prose li::marker { color: var(--colour-text-muted); }

strong, b { font-weight: var(--weight-bold); }

small { font-size: var(--text-small); line-height: var(--leading-small); }

img,
svg,
video,
picture {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Wide content scrolls inside its own box rather than the page. */
pre, table { max-width: 100%; overflow-x: auto; }

hr {
  border: 0;
  border-top: 1px solid var(--colour-rule);
  margin-block: var(--space-2xl);
}

/* ============================================================================
   Links
   ========================================================================== */

/* Every rule in this block excludes <a class="btn">: buttons carry their own
   ink, and a bare a:hover (0,1,1) would outrank .btn--primary (0,1,0) and turn
   a hovered button's text charcoal — 2.74:1 on terracotta-dark. The exclusion
   sits inside :where() so it adds no specificity; a plain :not(.btn) would
   lift these rules above every single-class link override (.brand, .skip-link,
   .play-badge). */
:where(a:not(.btn)) {
  color: var(--colour-link);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: color var(--transition-fast),
              text-decoration-color var(--transition-fast);
}

:where(a:not(.btn)):hover {
  color: var(--colour-link-hover);
  text-decoration-thickness: 2px;
}

/* Links inside the footer or any dark band. Terracotta on charcoal is only
   3.86:1, so it is not allowed here — cream at 14.74:1 is. */
.on-dark :where(a:not(.btn)) {
  color: var(--colour-text-inverse);
}

.on-dark :where(a:not(.btn)):hover {
  color: var(--colour-text-inverse-muted);
}

/* ============================================================================
   Buttons
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  min-height: var(--control-min-height);
  padding: var(--space-m) var(--space-xl);
  border: 0;
  border-radius: var(--radius-button);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  font-weight: var(--weight-bold);
  line-height: 1;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: filter var(--transition-fast),
              transform var(--transition-fast),
              box-shadow var(--transition-fast);
}

/* Terracotta-dark, not terracotta. White on #C4622D is 4.09:1 and fails AA;
   white on #A04F22 is 5.78:1 and passes. */
.btn--primary {
  background-color: var(--colour-button-primary);
  color: var(--colour-button-primary-ink);
}

/* Hover darkens rather than lightens, so contrast only ever improves —
   brightness(0.93) takes white-on-fill from 5.78:1 to 6.46:1. This is a render
   effect on an existing token, not a new colour. */
.btn--primary:hover { filter: brightness(0.93); }

.btn--secondary {
  background-color: var(--colour-button-secondary);
  color: var(--colour-button-secondary-ink);
}

.btn--secondary:hover { filter: brightness(0.96); }

.btn:active { transform: translateY(1px); }

.btn[disabled],
.btn[aria-disabled='true'] {
  opacity: 0.5;
  cursor: not-allowed;
  filter: none;
  transform: none;
}

/* ============================================================================
   Focus — keyboard only, never removed
   ========================================================================== */

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

/* Rounds the ring on plain text links. Deliberately not on the universal rule
   above: a border-radius there outranks .btn's own and reshapes a button from
   16px to 8px corners the moment it takes keyboard focus. */
:where(a:not(.btn)):focus-visible { border-radius: var(--radius-s); }

/* The offset gap shows the page ground, so the ring is measured against cream
   at 14.74:1 rather than against the control it surrounds. */
.on-dark :focus-visible {
  outline-color: var(--colour-focus-ring-inverse);
}

/* Mouse users do not get a ring, but :focus-visible handles that on its own —
   so nothing here suppresses :focus for browsers that lack it. */

/* Skip link — visible the moment it takes focus. */
.skip-link {
  position: absolute;
  top: var(--space-xs);
  left: var(--space-xs);
  z-index: 100;
  padding: var(--space-s) var(--space-m);
  background-color: var(--colour-charcoal);
  color: var(--colour-text-inverse);
  border-radius: var(--radius-s);
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus-visible { transform: translateY(0); }

/* ============================================================================
   Layout utilities
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--section-y); }
.section--hero { padding-block: var(--section-y-hero); }
.section--alt { background-color: var(--colour-page-alt); }
.section--accent { background-color: var(--colour-page-accent); }

.section--dark {
  background-color: var(--colour-footer);
  color: var(--colour-text-inverse);
}

.card {
  background-color: var(--colour-card);
  border-radius: var(--radius-card);
  padding: var(--space-l);
  box-shadow: var(--shadow-card);
  /* Deliberately no border. Tonal contrast separates the card from the ground —
     the app's STYLE.md rule 1. */
}

/* A white card on a white band would vanish, so it steps down a tone instead. */
.section--alt .card { background-color: var(--colour-card-on-alt); }

.eyebrow {
  font-size: var(--text-eyebrow);
  font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--colour-text-muted);
}

/* Bold variant for a tag or flag that labels a block rather than introduces one. */
.eyebrow--strong { font-weight: var(--weight-bold); }

.text-muted { color: var(--colour-text-muted); }

/* Escape hatch for the measure cap on <p>, e.g. a centred hero standfirst
   that is already constrained by its container. */
.u-measure-none { max-width: none; }

/* Grid and flex children default to min-width:auto, which is the usual cause of
   a page that scrolls sideways on a narrow phone. */
.u-min-width-0 { min-width: 0; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ============================================================================
   Reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
