/* ============================================================================
   Own Dine — design tokens
   ----------------------------------------------------------------------------
   Single source of truth for every colour, size and typeface in the product.
   Change a value here and it changes everywhere. Never hard-code a colour in a
   component — always reference a token.

   >>> AFTER ANY CHANGE TO THIS FILE, RUN:  node brand/check-contrast.js <<<
   It asserts every pair that appears on screen, under normal light AND under
   simulated kitchen glare. A wordmark defect shipped once because a colour was
   checked against the wrong background; that test exists so it cannot recur.

   FIVE RULES THAT MUST NOT BE BROKEN (reasoning in OWNDINE-BRAND.md):

   1. Brand green never signals meaning. It is chrome and actions only. Order
      state comes from the --od-status-* tokens, never from green.

   2. --od-provider-accent is the ONLY token a provider may override, and it
      applies to the customer ordering widget only. It must never reach the Hub
      order board. A restaurant choosing red as their brand colour must not be
      able to repaint a board where red means "this order is late".

   3. Status colours are fixed. Not themeable, not configurable. The late
      treatment is identical in light and dark mode by design.

   4. The action green carries DARK labels, not white. White on #25D366 scores
      1.98 and vanishes. This inversion is the whole point of the palette: deep
      green does the reading, vivid green does the doing.

   5. The Hub is used under bright fluorescent light, which lifts the screen's
      black level and collapses measured contrast by roughly a third. Nothing
      on the Hub may sit on the 4.5 floor — it must clear it under glare too.
   ========================================================================== */

:root {

  /* ---- Brand: Action green ---------------------------------------------- */
  /* Hue ~142deg, deliberately blue-leaning. A yellow-green drifts towards
     olive under warm restaurant lighting and evening night-mode filters;
     this one keeps its identity because it has blue to spare. */
  --od-green-50:  #ECFBF3;
  --od-green-100: #C9F5DD;
  --od-green-200: #96EBBD;
  --od-green-300: #5FE099;  /* links on dark surfaces */
  --od-green-400: #3FE07F;  /* "Own" on dark; button hover */
  --od-green-500: #25D366;  /* PRIMARY ACTION. Dark label only. */
  --od-green-600: #1DAE53;  /* pressed / borders. NOT a hover: see below. */
  --od-green-700: #0F5A32;  /* links and "Own" on white (8.30:1) */
  --od-green-800: #14472B;  /* mid-dark surfaces */
  --od-green-900: #0E3320;  /* dark surfaces; the Hub bar in DARK mode */

  /* Buttons BRIGHTEN on hover (500 -> 400), they do not darken. With a dark
     label, going darker reduces contrast — #1DAE53 fails under glare at 3.83. */

  /* ---- Neutrals (faint green undertone, so they sit with the brand) ------ */
  --od-grey-50:  #FAFCFB;
  --od-grey-100: #F1F5F2;
  --od-grey-200: #E2E9E5;
  --od-grey-300: #C9D4CD;
  --od-grey-400: #A0AEA6;
  --od-grey-500: #78877F;
  --od-grey-600: #4A564F;   /* muted text — 7.68:1, holds under glare */
  --od-grey-700: #36403A;
  --od-grey-800: #212925;
  --od-grey-900: #101613;   /* body ink, "Dine", the wordmark underscore */

  /* ---- Order status — FIXED. Never overridable. ------------------------- */
  /* Differentiation is carried on three axes at once: hue, text colour, and
     the weight of the whole tile. Colour alone cannot separate "due soon" from
     "late" across a kitchen — orange and red are neighbouring hues, and a warm
     evening filter pushes them closer still. What survives any filter is the
     2.63x LIGHTNESS gap and the fact that a late order fills the entire tile. */

  --od-status-ontime:      #475467;
  --od-status-ontime-text: #FFFFFF;   /* 7.69 / 4.73 under glare */

  --od-status-soon:        #FDB022;
  --od-status-soon-text:   #4A1A04;   /* near-black, 7.92 / 5.02 */

  --od-status-late:        #D92D20;
  --od-status-late-text:   #FFFFFF;   /* 4.83 / 3.77 — LARGE TEXT ONLY */
  --od-status-late-edge:   #8C1710;
  /* The late tile's text MUST be set large (>=18.66px bold or >=24px). At
     normal size it fails under glare. Large text needs only 3:1, which it
     clears. This is not optional styling — it is what makes the most urgent
     tile readable over a fryer. Enforced by .od-tile--late.
     #D92D20 is also the brightest red that carries white text at all;
     #EF4444 drops to 3.76 even in good light. If louder is ever wanted, the
     answer is a pulsing tile, not a brighter red. */

  /* A pale red ground for the CUSTOMER's "not accepted" panel and the stale
     notice on the status page. Never the Hub board: a late tile fills with
     --od-status-late at full strength and that is the point of it. Body ink is
     16.85 on this and muted text 7.06. */
  --od-status-late-tint:   #FEF3F2;

  --od-status-ahead-border: #98A2B3;  /* dashed */
  --od-status-ahead-bg:     #EAECF0;
  --od-status-ahead-text:   #3A4454;  /* 8.32 / 5.00 */
  /* "Ordered ahead" must be the quietest object on the board. It is the one
     state requiring no action. Do not make it vivid. */

  /* ---- "This went well" — the CUSTOMER's order status page only ----------
     Added 2026-09-29. It was already on screen as a bare #2f6b45 in order.css
     with no name; this gives it one and changes nothing visually.

     It is NOT part of the --od-status-* family above and must never appear on
     the Hub's order board, where §4.3 of OWNDINE-BRAND.md is absolute: colour
     means urgency, never stage.

     It is also NOT brand green, deliberately. Brand green never signals
     meaning, and on a customer page it would additionally collide with
     --od-provider-accent, which a shop may set to anything.

     It is used as a 4px left edge beside a bold sentence that already states
     the outcome ("Ready to collect", "All done"), so it SUPPORTS the words
     rather than carrying them. That distinction is what lets it sit closer in
     lightness to the other two edges than the board's 2.0 separation rule
     allows — nobody reads this across a kitchen. */
  --od-positive: #2f6b45;   /* 6.16 on the status panel; meaningful graphic, min 3.0 */

  /* ---- Semantic surfaces — light ---------------------------------------- */
  --od-surface:         #FFFFFF;
  --od-surface-sunken:  var(--od-grey-50);
  --od-surface-brand:   var(--od-green-50);
  --od-surface-inverse: var(--od-green-700);   /* Hub brand bar. Was green-900;
                                                  lightened 3x on 2026-09-07 because
                                                  near-black read as a heavy slab.
                                                  See OWNDINE-BRAND.md 4.6. */
  --od-border:          var(--od-grey-200);
  --od-border-strong:   var(--od-grey-300);

  --od-text:            var(--od-grey-900);
  --od-text-muted:      var(--od-grey-600);
  --od-text-subtle:     var(--od-grey-500);
  --od-text-inverse:    #FFFFFF;
  --od-text-brand:      var(--od-green-700);

  --od-action:          var(--od-green-500);
  --od-action-hover:    var(--od-green-400);   /* brighter, not darker */
  --od-action-text:     #04250F;               /* dark label. Never white. */
  --od-focus-ring:      var(--od-green-600);

  /* ---- Widget colour — set per shop, defaults here ---------------------- */
  /*
     These four are what a restaurant may recolour (spec section 14). They apply
     to the customer ordering widget and must never reach the Hub order board.

     >>> --od-provider-on-accent CANNOT STAY A FIXED VALUE <<<

     It is the label that sits ON the provider colour. #04250F is correct for the
     Own Dine default (8.29:1) and for light accents, and badly wrong for dark
     ones. Measured against real brand colours a restaurant might pick:

         Own Dine #25D366   dark 8.29 PASS      white 1.98
         orange   #F26722   dark 5.28 PASS      white 3.12
         pink     #E91E8C   dark 3.94 FAIL      white 4.18 FAIL  <- neither works
         forest   #1B4332   dark 1.48 FAIL      white 11.08
         maroon   #6A1B1A   dark 1.40 FAIL      white 11.77
         navy     #14213D   dark 1.03 FAIL      white 15.97
         black    #111111   dark 1.15 FAIL      white 18.88

     A navy-branded restaurant would get a Checkout button whose label is
     invisible — on the one screen where a customer is trying to pay.

     BUILT 2026-09-07. src/lib/brand/provider-accent.ts chooses the label from
     the accent, and nudges the accent when it carries neither — the pink row
     above. A shop picks its colour at /hub/settings/brand; the Hub computes all
     four values on save and stores them on `providers`; the ordering page reads
     them and sets these variables on a wrapper.

     So the values below are DEFAULTS, for a shop that has not chosen. Do not
     make them settable anywhere else, and do not reimplement the label choice:
     the customer ordering app is a separate Next application that cannot import
     the Hub's lib, which is exactly why the result is stored rather than
     derived at render time.
  */
  --od-provider-accent:      var(--od-green-500);
  --od-provider-accent-dark: var(--od-green-700);
  --od-provider-tint:        var(--od-green-50);
  --od-provider-on-accent:   #04250F;   /* DEFAULT ONLY - a shop that has picked overrides this */

  /* ---- Type ------------------------------------------------------------- */
  --od-font-ui:   "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --od-font-mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;
  /* Order numbers, prices and times ALWAYS use --od-font-mono, so digits are
     the same width and columns line up on a board of forty tickets. */

  --od-text-xs:   11.5px;
  --od-text-sm:   13px;
  --od-text-base: 15px;
  --od-text-lg:   17px;
  --od-text-xl:   21px;
  --od-text-2xl:  25px;
  --od-text-3xl:  31px;
  --od-text-4xl:  38px;

  /* The threshold at which WCAG treats text as "large" and the requirement
     drops from 4.5:1 to 3:1. The late tile depends on this. */
  --od-text-large-bold: 19px;

  --od-weight-regular:  400;
  --od-weight-medium:   500;
  --od-weight-semibold: 600;
  --od-weight-bold:     700;

  --od-leading-tight: 1.2;
  --od-leading-body:  1.6;
  --od-tracking-display: -0.02em;

  /* ---- Shape and space -------------------------------------------------- */
  --od-radius-sm:   4px;
  --od-radius:      6px;
  --od-radius-lg:   10px;
  --od-radius-xl:   18px;
  --od-radius-pill: 99px;

  --od-space-1: 4px;   --od-space-2: 8px;   --od-space-3: 12px;
  --od-space-4: 16px;  --od-space-5: 20px;  --od-space-6: 24px;
  --od-space-8: 32px;  --od-space-10: 40px; --od-space-12: 48px;

  /* Minimum touch target. The Hub is used one-handed on a tablet with wet
     hands — never go below this for anything tappable. */
  --od-target-min: 44px;

  /* ---- Elevation ---------------------------------------------------------
     Added 2026-09-04. Until then the product had no depth at all: every card
     was a 1px --od-border line on --od-surface-sunken, which is a 2% step. On
     the cheap tablet this is really used on, under the fluorescent light that
     rule 5 is about, that step disappears and the whole screen reads as one
     flat sheet with nothing on it standing forward.

     Two things make these sit with the brand rather than on top of it:

       1. The shadow colour is the ink, #101613, not black. These neutrals
          carry a green undertone, and a neutral-black shadow over them goes
          grey and dirty — which is exactly the cheap-admin-panel look.
       2. Every level is two shadows: a tight one doing the work of the
          border, and a wide soft one doing the lifting. One shadow asked to
          do both is what makes a card look like a sticker.

     --od-shadow-brand is for a surface that is deliberately branded, such as
     the current navigation item. It is still elevation, never meaning —
     rule 1 stands: green may not tell anybody the state of anything.
     ------------------------------------------------------------------------ */
  --od-shadow-sm:    0 1px 2px rgb(16 22 19 / 0.05), 0 1px 1px rgb(16 22 19 / 0.04);
  --od-shadow:       0 1px 2px rgb(16 22 19 / 0.06), 0 4px 12px rgb(16 22 19 / 0.06);
  --od-shadow-lg:    0 2px 6px rgb(16 22 19 / 0.08), 0 14px 32px rgb(16 22 19 / 0.10);
  --od-shadow-brand: 0 1px 2px rgb(15 90 50 / 0.10), 0 6px 18px rgb(15 90 50 / 0.14);
}

/* ============================================================================
   Dark mode — Hub only.
   The customer ordering widget is ALWAYS light: it sits inside the provider's
   own website and should not fight their styling.
   Scope: data-od-theme="dark" on the Hub root, never on <html>, so it cannot
   leak into an embedded widget.
   ========================================================================== */
[data-od-theme="dark"] {
  --od-surface:         #18211B;
  --od-surface-sunken:  #0C120E;
  --od-surface-brand:   #16241C;
  --od-surface-inverse: var(--od-green-900);
  --od-border:          #243026;
  --od-border-strong:   #2D3B31;

  --od-text:            #EFF4EC;
  --od-text-muted:      #9EAEA3;
  --od-text-subtle:     #7D8D83;
  --od-text-inverse:    var(--od-grey-900);
  --od-text-brand:      var(--od-green-300);

  --od-action:          var(--od-green-500);
  --od-action-hover:    var(--od-green-400);
  --od-focus-ring:      var(--od-green-300);

  --od-status-ahead-border: #4A5A50;
  --od-status-ahead-bg:     #242E28;
  --od-status-ahead-text:   #C3D0CB;
  /* --od-status-late and --od-status-soon are deliberately NOT overridden.
     A late order must look identical in either mode. */

  /* A shadow over a dark ground is nearly invisible — there is no light left
     to take away. Depth in dark mode comes from the surface being lighter
     than the page behind it, so these go deeper and tighter and the borders
     carry more of the load. */
  --od-shadow-sm:    0 1px 2px rgb(0 0 0 / 0.40);
  --od-shadow:       0 1px 2px rgb(0 0 0 / 0.45), 0 4px 12px rgb(0 0 0 / 0.35);
  --od-shadow-lg:    0 2px 6px rgb(0 0 0 / 0.50), 0 14px 32px rgb(0 0 0 / 0.45);
  --od-shadow-brand: 0 1px 2px rgb(0 0 0 / 0.45), 0 6px 18px rgb(37 211 102 / 0.16);
}

/* ============================================================================
   The late tile — the large-text rule made real.
   ========================================================================== */
.od-tile--late {
  background: var(--od-status-late);
  border-color: var(--od-status-late);
  border-left-color: var(--od-status-late-edge);
  color: var(--od-status-late-text);
}
.od-tile--late .od-tile__number,
.od-tile--late .od-tile__status {
  font-size: var(--od-text-large-bold);   /* >=19px */
  font-weight: var(--od-weight-bold);     /* qualifies as WCAG "large text" */
}

/* ============================================================================
   Wordmark — the logo, as live text.
   Accurate because the browser sets it. Use this on the web; use the outlined
   SVG for email, print, and anywhere the font cannot load.

     <span class="od-wordmark"><b>Own</b>Dine<i></i></span>
     <span class="od-wordmark" data-on="dark"><b>Own</b>Dine<i></i></span>

   "Own" is ALWAYS green. Only the underscore changes — near-black on light,
   white on dark.
   ========================================================================== */
.od-wordmark {
  font-family: var(--od-font-ui);
  font-size: var(--od-text-3xl);
  line-height: 1;
  letter-spacing: -0.022em;
  white-space: nowrap;
  display: inline-flex;
  align-items: baseline;
  gap: 0.24em;
  color: var(--od-grey-900);               /* "Dine" */
}
.od-wordmark > b {                         /* "Own" */
  font-weight: var(--od-weight-bold);
  color: var(--od-green-700);              /* 8.30:1 on white */
  border-bottom: 0.078em solid var(--od-grey-900);   /* scales with type */
  padding-bottom: 0.09em;
}
.od-wordmark > i {                         /* the square full stop */
  width: 0.19em;
  height: 0.19em;
  background: var(--od-green-500);         /* vivid — this is the accent */
  display: inline-block;
  margin-left: -0.14em;
  font-style: normal;
}
/* The dot is vivid green on white, which measures 1.98:1. That is deliberate
   and acceptable: it is a decorative element of the logo, carries no
   information, and logos are exempt from WCAG contrast requirements. It must
   never be the only thing communicating something. */

/* On a NEAR-BLACK surface, "Own" keeps its green. */
.od-wordmark[data-on="dark"] { color: #FFFFFF; }
.od-wordmark[data-on="dark"] > b {
  color: var(--od-green-400);              /* 10.90:1 on #0D1310 */
  border-bottom-color: #FFFFFF;
}
.od-wordmark[data-on="dark"] > i { background: var(--od-green-400); }

/* ---------------------------------------------------------------------------
   On the BRAND BAR (--od-surface-inverse, green-700) "Own" is WHITE.

   This is the one place the "Own is always green" rule in section 3.1 of
   OWNDINE-BRAND.md does not hold, and it is not a preference. On green-700 no
   green in the palette clears 4.5:1 as text: green-400 scores 3.27 under
   kitchen glare, green-300 3.39, green-200 3.91, green-100 4.47. Only white
   passes, at 8.30 / 5.16.

   The green does not leave the wordmark, it moves: the square full stop stays
   green-400, which scores 4.82 / 3.27 and only needs 3:1 because it is a
   graphic rather than text.
   --------------------------------------------------------------------------- */
.od-wordmark[data-on="brand"] { color: var(--od-text-inverse); }
.od-wordmark[data-on="brand"] > b {
  color: var(--od-text-inverse);
  border-bottom-color: var(--od-text-inverse);
}
.od-wordmark[data-on="brand"] > i { background: var(--od-green-400); }

/* Minimum legible sizes. Below these, use the app mark instead. */
.od-wordmark--sm { font-size: var(--od-text-xl); }
.od-wordmark--xs { font-size: var(--od-text-base); }
