/*
 * The platform stylesheet: every client's pages load it first, then their own theme (/theme.css,
 * or /css/theme-platform.css with no client), which brings the fonts, every design token and the
 * client's brand rules. No build step: served as-is from /css/base.css.
 */

/* ------------------------------------------------------------------ tokens
   Only the grid lives here, because the media queries right below redefine it; every other token
   comes from the client's theme. */
:root { --ui-grid-cols: 4; --ui-grid-gutter: 16px; --ui-grid-margin: 16px; }

@media (min-width: 600px) { :root { --ui-grid-cols: 8; --ui-grid-gutter: 20px; --ui-grid-margin: 40px; } }
@media (min-width: 1136px) { :root { --ui-grid-cols: 12; --ui-grid-gutter: 20px; --ui-grid-margin: 80px; } }

/* ------------------------------------------------------------------ THE WEBSITE DESIGN SYSTEM
 *
 * One product, two surfaces.
 *
 * The kiosk's design system lives at the top of public/css/kiosk.css and is pinned by
 * tests/Feature/Kiosk/KioskDesignSystemTest.php. This is that SAME system at website scale, not
 * a second one: the same four-step rhythm, the same single selected treatment, the same
 * image-to-text ratio, the same currency, the same three typographic jobs. Where a value here
 * differs from the kiosk's it differs for exactly one reason — a mouse and a phone are not a
 * finger at arm's length on a low-density panel — and the line says so.
 *
 * The design review that produced this block found the same defect the kiosk review found, on a
 * different surface: not any single control, but that the desktop pages were compressed while
 * the mobile product and checkout screens were vertically heavy, so the two surfaces read as two
 * products. Nothing about the identity changed. Red, black, white, the photography and the
 * display italic are KFC's and are untouched; what this defines is how much room each gets.
 */
:root {
    /* --- rhythm: the kiosk's four steps, written in the website's own scale of 4 --------------
       Kiosk 8 / 16 / 24 / 40 ARE --ui-space-2 / 4 / 6 / 10. Aliasing them rather than
       redeclaring the numbers is the whole point: there is one scale in the building. */
    --w-gap-tight: var(--ui-space-2);      /* 8  — inside one control: icon to label, label to price */
    --w-gap-inline: var(--ui-space-4);     /* 16 — between controls sitting on one line */
    --w-gap-block: var(--ui-space-6);      /* 24 — between rows of a list, between cards */
    --w-gap-section: var(--ui-space-10);   /* 40 — between one section of a page and the next */

    /* --- pointer: the ONE deliberate divergence from the kiosk --------------------------------
       --k-tap is 104px because a cabinet is a large low-density panel at arm's length, with no
       hover and no keyboard. A phone or a mouse is neither. 48px is the existing --tap and is
       what a thumb wants; 44px is WCAG 2.5.5 and is the floor for a control that sits INSIDE a
       bar or a row, where 48 would push the bar taller than the content it acts on. */
    --w-tap: var(--tap);                    /* 48 — a standalone tappable thing */
    --w-tap-inline: 44px;                   /* a control inside a bar or a list row */

    /* --- choice: ONE selected treatment, and it is the kiosk's --------------------------------
       Red line, light red fill, and a mark that is present-but-empty when nothing is chosen, so
       an unanswered question looks unanswered rather than absent. Colour alone is not a state.
       The fill is the kiosk's own --k-chosen-fill and is written out exactly once, below. */
       KFC's Digital Guidelines (ui-border, stated) put the LINE of a selected card at 1px Grey 900
       and a checked box in Brand Red with a white tick; the line follows the guideline now, the
       red lives in the mark, and the light fill stays the kiosk's. */
    --w-chosen-line: var(--ui-grey-900);
    --w-chosen-fill: #FFF4F5;
    --w-chosen-width: var(--ui-border-100);
    --w-chosen-mark: 20px;                  /* the kiosk's 40px mark, at pointer scale */
    --w-chosen-mark-fill: var(--ui-primary);  /* checkbox / radio checked: Brand Red + white tick (stated) */

    /* --- cards: one image-to-text ratio -------------------------------------------------------
       The kiosk fixes a tile's photograph and its body in pixels because its grid is fixed. A
       website grid is fluid, so the same proportion is held as a ratio plus a RESERVED text
       block — which is what makes the name, the price and the action line up across a row
       whatever length of name the POS sends. */
    --w-card-media: 4 / 3;                  /* every product photograph, in a card or on a page */
    --w-card-name: 3;                       /* the product name runs to at most three lines (KFC card spec) */
    --w-card-desc: 40px;                    /* two lines of the description, reserved */
    --w-thumb: 56px;                        /* cart and order-summary line thumbnail */

    /* --- type: three faces, three jobs, the same three as the kiosk ---------------------------
         stripes  the category divider and the section transition, Hero size and up only
         serif    HEADINGS, the product name on a product CARD (KFC's card spec), and the
                  primary CTA label — Kentucky Fried Sans ships Light and Regular only, so a
                  sans CTA would be a weaker button, not a cleaner one
         sans     everything a customer READS rather than scans: descriptions, option labels,
                  prices, cart lines, form fields, captions

       The card name was sans Title Case for a while, to stop the POS's mixed casing showing;
       KFC's Digital Guidelines set it in Serif caps, which flattens the casing anyway. Pinned by
       WebsiteDesignSystemTest. */
    --w-type-category: var(--t-hero-xxl);   /* the Stripes category divider: Hero-XXL, 96 -> 120 (never under Hero 72) */
    --w-type-item: clamp(16px, calc(16px + 6 * (100vw - 390px) / 746), 22px);  /* a product's name: H5 -> H4 */
    --w-type-money: 16px;                   /* an inline price */
}
@media (min-width: 1136px) {
    :root {
        --w-type-money: 18px;
        --w-card-desc: 20px; --w-thumb: 64px;
    }
}

/* The mark. Exactly the kiosk's `.k-option-mark` at pointer scale: a box that is ALWAYS in the
   row, empty, so an unanswered question looks unanswered rather than absent; filled with the
   chosen colour when it is answered. It is decoration — the state a screen reader is told is
   `aria-pressed` / `:checked` on the control itself. */
.chosen-mark {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    width: var(--w-chosen-mark); height: var(--w-chosen-mark);
    border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-40);
    background: var(--ui-white); color: transparent;
}
.chosen-mark svg { width: 14px; height: 14px; }
[aria-pressed="true"] > .chosen-mark, [aria-pressed="true"] .chosen-mark {
    border-color: var(--w-chosen-mark-fill); background: var(--w-chosen-mark-fill); color: var(--ui-white);
}

/* ------------------------------------------------------------------ checkbox and radio (one component)
   KFC ui-border (stated): default 1px Grey 300 box — we use the control line (Grey 400, WCAG 1.4.11,
   see --ui-control-line) — checked = Brand Red fill and a white tick. Radius 4 like every control,
   and a radio is the SAME box: KFC's "Radio Button Default" (ui-border 03) is a square, and the guide
   shows no circle anywhere. Drawn once, here, for every native checkbox and radio on the site. */
input[type="checkbox"], input[type="radio"] {
    -webkit-appearance: none; appearance: none; flex: none; width: 22px; height: 22px; margin: 0; cursor: pointer;
    border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-40); background: var(--ui-white);
    display: inline-grid; place-content: center; vertical-align: middle;
}
input[type="checkbox"]:checked, input[type="radio"]:checked { border-color: var(--w-chosen-mark-fill); background: var(--w-chosen-mark-fill); }
input[type="checkbox"]:checked::before, input[type="radio"]:checked::before { content: ""; width: 12px; height: 12px; background: var(--ui-white);
    clip-path: polygon(14% 52%, 0 66%, 38% 100%, 100% 22%, 86% 8%, 38% 72%); }
input[type="checkbox"]:disabled, input[type="radio"]:disabled { border-color: var(--ui-grey-200); background: var(--ui-grey-50); cursor: not-allowed; }
input[type="checkbox"]:hover:not(:disabled), input[type="radio"]:hover:not(:disabled) { border-color: var(--ui-black); }

/* ------------------------------------------------------------------ base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--ui-canvas);
    color: var(--ui-text);
    font-family: var(--ui-font-body);
    font-weight: 300;              /* Body 1: Sans Light 16/24 */
    font-size: 16px;
    line-height: 24px;
    letter-spacing: 0;
    font-synthesis-weight: none;   /* no faux bold: KFC Sans has Light + Regular only */
    -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }
strong, b { font-weight: 400; }    /* emphasis = Sans Regular against Light body */

/* Focus (stated): 2.5px black ring, 4px padding, 4px radius. White on the black header. */
/* No border-radius here: changing an element's own radius on focus reshapes it. The ring follows the element's radius. */
:focus-visible { outline: var(--ui-focus-width) solid var(--ui-focus); outline-offset: var(--ui-focus-padding); }
/* A text link's ring is the stated one: 2.5px black, 4px padding, 4px radius (ui-border, focus).
   (Only on elements with no fill of their own, so the radius cannot reshape anything.) */
a:not([class]):focus-visible, .text-link:focus-visible, .link-button:focus-visible, .prose a:focus-visible, .nav-link:focus-visible,
.nav-account:focus-visible, .nav-order:focus-visible { border-radius: var(--ui-focus-radius); }
.site-header :focus-visible, .cart-bar-checkout :focus-visible, .tab-bar :focus-visible, .hero :focus-visible { outline-color: var(--ui-white); }

.visually-hidden {
    position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;   /* hairline: the standard visually-hidden clip */
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link { position: absolute; left: 8px; top: -60px; z-index: 50; background: var(--ui-white); padding: var(--ui-space-3) var(--ui-space-4); }
.skip-link:focus { top: 8px; }

/* Layout container on the stated grid: 4/8/12 columns, margins 16/40/80. */
.wrap { max-width: var(--ui-page-max); margin: 0 auto; padding: 0 var(--ui-grid-margin); }
.grid { display: grid; grid-template-columns: repeat(var(--ui-grid-cols), minmax(0, 1fr)); column-gap: var(--ui-grid-gutter); }

.icon { flex: none; display: inline-block; vertical-align: middle; }
.icon-md { width: var(--ui-icon-md); height: var(--ui-icon-md); }
.icon-sm { width: var(--ui-icon-sm); height: var(--ui-icon-sm); }
.icon-xs { width: var(--ui-icon-xs); height: var(--ui-icon-xs); }

/* ------------------------------------------------------------------ typescale
   ONE table, every style KFC names, as a token pair: a MOBILE value at 390px and the DESKTOP value
   at 1136px, and clamp() between them — "dynamic typescaling" rather than a jump at a breakpoint.

   DESKTOP column = STATED (portal > UI Typography > Specs, Desktop tab).
   MOBILE column  = ASSUMED. The Mobile tab was never captured. Derived from KFC's own step list
                    (10 12 14 16 20 22 24 28 40 52 72 96 120 214) one or two steps down, with two
                    floors that are rules rather than guesses: Stripes never below Hero (72px,
                    "Mega and Hero sizes only"), and reading text never below 16px. Replace this
                    column, and nothing else, when the Mobile tab is captured.

     style       face     mobile (ASSUMED)  desktop (STATED)   notes
     Mega-L      Stripes  120 / 108          280 / 260
     Mega        Stripes  120 / 108          214 / 194
     Hero-XXL    Stripes   96 /  86          120 / 108
     Hero-XL     Stripes   72 /  68           96 /  86
     Hero        Stripes   72 /  68           72 /  68          the Stripes floor
     H1          Serif     40 /  40           52 /  52          one step down
     H2          Serif     28 /  28           40 /  40          one step down
     H3          Serif     24 /  24           32 /  32          32 is not on the step list; 24 is
     H4          Serif     20 /  20           22 /  22          +0.25px tracking (stated)
     H5          Serif     16 /  16           16 /  16          +0.25px tracking (stated)
     Subtitle 1  Sans L    16 /  24           18 /  24
     Subtitle 2  Sans L    14 /  20           14 /  20
     Body 1      Sans L    16 /  24           16 /  24          the page body
     Body 2      Sans L    14 /  24           14 /  24
     Caption     Sans L    12 /  16           12 /  16
     Overline    Sans R    12 /  16           12 /  16          caps
     Button      Serif     16 /  24           16 /  24          primary CTA uses --ui-cta-size (WCAG, above)
     Button S    Serif     14 /  16           14 /  16

   Serif headings are set SOLID (line-height = size, stated): KFC's headings are tight, and the
   earlier 1.2-1.4 line-heights are what made the pages read airy next to kfc-aruba.com. */
:root {
    --ui-fluid: (100vw - 390px) / 746;   /* 0 at 390px, 1 at 1136px */
    --t-mega-l: clamp(120px, calc(120px + 160 * var(--ui-fluid)), 280px);
    --t-mega: clamp(120px, calc(120px + 94 * var(--ui-fluid)), 214px);
    --t-hero-xxl: clamp(96px, calc(96px + 24 * var(--ui-fluid)), 120px);
    --t-hero-xl: clamp(72px, calc(72px + 24 * var(--ui-fluid)), 96px);
    --t-hero: 72px;
    --t-h1: clamp(40px, calc(40px + 12 * var(--ui-fluid)), 52px);
    --t-h2: clamp(28px, calc(28px + 12 * var(--ui-fluid)), 40px);
    --t-h3: clamp(24px, calc(24px + 8 * var(--ui-fluid)), 32px);
    --t-h4: clamp(20px, calc(20px + 2 * var(--ui-fluid)), 22px);
    --t-h5: 16px;
    --t-subtitle-1: clamp(16px, calc(16px + 2 * var(--ui-fluid)), 18px);
}
.kfc-mega-l, .kfc-mega, .kfc-hero-xxl, .kfc-hero-xl, .kfc-hero {
    font-family: var(--ui-font-display); font-weight: 900; font-style: normal; text-transform: uppercase; letter-spacing: 0;
}
.kfc-h1, .kfc-h2, .kfc-h3, .kfc-h4, .kfc-h5, .kfc-button, .kfc-button-sm,
h1, h2, h3, h4, .heading {
    font-family: var(--ui-font-heading); font-weight: 900; font-style: italic; text-transform: uppercase; letter-spacing: 0; margin: 0;
}
.kfc-subtitle-1, .kfc-subtitle-2, .kfc-body-1, .kfc-body-2, .kfc-caption, .kfc-overline { font-family: var(--ui-font-body); font-style: normal; letter-spacing: 0; }

.kfc-mega-l { font-size: var(--t-mega-l); line-height: .93; }      /* 260/280 */
.kfc-mega { font-size: var(--t-mega); line-height: .9; }            /* 194/214 */
.kfc-hero-xxl { font-size: var(--t-hero-xxl); line-height: .9; }    /* 108/120 */
.kfc-hero-xl { font-size: var(--t-hero-xl); line-height: .9; }      /* 86/96 */
.kfc-hero { font-size: var(--t-hero); line-height: 68px; }
.kfc-h1, h1 { font-size: var(--t-h1); line-height: 1; }
.kfc-h2, h2 { font-size: var(--t-h2); line-height: 1; }
.kfc-h3, h3 { font-size: var(--t-h3); line-height: 1; }
.kfc-h4, h4 { font-size: var(--t-h4); line-height: 1; letter-spacing: .25px; }
.kfc-h5 { font-size: var(--t-h5); line-height: 1; letter-spacing: .25px; }
.kfc-subtitle-1 { font-weight: 300; font-size: var(--t-subtitle-1); line-height: 24px; }
.kfc-subtitle-2 { font-weight: 300; font-size: 14px; line-height: 20px; }
.kfc-body-1 { font-weight: 300; font-size: 16px; line-height: 24px; }
.kfc-body-2 { font-weight: 300; font-size: 14px; line-height: 24px; }
.kfc-caption { font-weight: 300; font-size: 12px; line-height: 16px; }
.kfc-overline { font-weight: 400; font-size: 12px; line-height: 16px; text-transform: uppercase; }
.kfc-button { font-size: 16px; line-height: 24px; }
.kfc-button-sm { font-size: 14px; line-height: 16px; }

/* ------------------------------------------------------------------ Stripes: the category divider
   "Our iconic bucket stripes reimagined using typography... Only used with Mega and Hero sizes"
   (stated). Roles: the category divider on the PLP and the PDP, and the transition into another
   section. The word, in Brand Red, repeated end to end in a line that runs off both edges of the
   page; it translates horizontally as the page scrolls vertically (a parallax marquee).

   The heading IS the band: <h2 class="stripes"> carries the one real word for a screen reader,
   and the repeats beside it are aria-hidden. It is clipped by its own box, so it can never make
   the page scroll sideways. motion.js moves .stripes-track; with JavaScript off or reduced motion
   it simply stands still, starting at the grid margin like a heading. */
.stripes {
    display: block; overflow: hidden; white-space: nowrap; color: var(--ui-primary);
    font-family: var(--ui-font-display); font-weight: 900; font-style: normal; text-transform: uppercase; letter-spacing: 0;
    font-size: var(--w-type-category); line-height: .9; margin: 0;
    /* Out of the .wrap to the page edges, then the first word back on the grid margin. */
    margin-left: calc(-1 * var(--ui-grid-margin)); padding-left: var(--ui-grid-margin);
    /* Runs past the right edge of the screen, whatever the container; <main> clips it there. */
    margin-right: -50vw;
    /* The Stripes face overhangs its em box on the slant; this keeps the clip off the glyphs. */
    padding-block: .06em .02em;
}
.stripes-track { display: inline-block; will-change: transform; }
.stripes-word { display: inline; }
/* The named band (partials/stripes): the first name whole in a box at most the column wide, the
   repeats in a clipped strip beside it that runs off the screen (main clips it) and is the only
   thing the marquee moves. The band's own font-size is the ceiling; the row starts at Hero 72,
   wrapping at its spaces, until motion.js fits it (fitStripes). */
.stripes-named { container-type: inline-size; overflow: visible; white-space: normal; margin-right: 0; }
.stripes-row { display: flex; align-items: flex-end; margin-right: -100vw; font-size: var(--t-hero); }
.stripes-named .stripes-word { flex: 0 1 auto; min-width: 0; max-width: 100cqi; white-space: normal; }
.stripes-rest { flex: 1 1 0; min-width: 0; overflow: hidden; white-space: nowrap; margin-left: .3em; }
.stripes-rest .stripes-track > span { margin-right: .25em; }


p { margin: 0 0 var(--ui-space-3); }
.muted { color: var(--ui-text-secondary); }
.small { font-size: 14px; line-height: 20px; }

/* ------------------------------------------------------------------ header: black bar, red lettermark
   KFC's own (plp-desktop-final / pdp-desktop / our-history): lettermark, three links in Sans
   Light at Subtitle size, the current one in Brand Red; on the right the account link with a
   Lucide user icon, START ORDER (or the order's pickup/delivery + restaurant, underlined, with a
   chevron) and the cart as a bucket with its count. Radius 0 (structural). On a phone the bar is
   the lettermark and START ORDER only: the rest is in the tab bar at the foot. */
.site-header { position: relative; background: var(--ui-black); color: var(--ui-white); border-radius: var(--ui-radius-none); }
/* QA E10: from 600px the header is sticky on scroll (as the guide draws it), so the bucket, its
   count and the drop animation are on screen when something is added from far down the menu.
   On a phone the cart is the red bar at the foot instead, and the screen height is kept.
   --header-h is what every other sticky thing and every anchor offsets by. */
:root { --header-h: 0px; }
@media (min-width: 600px) {
    :root { --header-h: 64px; }
    .site-header { position: sticky; top: 0; z-index: 30; }
    html { scroll-padding-top: var(--header-h); }
}
/* The header hugs the VIEWPORT, not the content grid (plp-desktop-final: lettermark ~36px from the
   left edge, the bucket ~48px from the right, at every width): its own edge margin, never capped. */
.site-header .wrap { display: flex; align-items: center; gap: var(--ui-space-4); min-height: 64px; max-width: none; padding: 0 var(--ui-grid-margin); }
@media (min-width: 1136px) { .site-header .wrap { padding: 0 var(--ui-space-9); } }
/* Lettermark clear space: 20% of its height on every side (32px mark -> 6.4px, padded to 8px). */
.logo { display: inline-flex; align-items: center; padding: var(--ui-space-2); margin-left: calc(-1 * var(--ui-space-2)); text-decoration: none; }
.logo img { height: 32px; width: auto; }
.site-nav { display: none; }
.site-nav a.nav-link {
    display: inline-flex; align-items: center; min-height: var(--tap); padding: 0 var(--ui-space-3);
    color: var(--ui-white); text-decoration: none; font-weight: 300; font-size: var(--t-subtitle-1); line-height: 24px; white-space: nowrap;
}
.site-nav a.nav-link:hover, .site-nav a.nav-link[aria-current="page"] { color: var(--ui-primary); }
.site-actions { display: flex; align-items: center; gap: var(--ui-space-4); margin-left: auto; }

.nav-account { align-items: center; gap: var(--ui-space-1); min-height: 44px; color: var(--ui-white); text-decoration: none; font-size: 14px; font-weight: 300; white-space: nowrap; }
.nav-account[aria-current="page"], .nav-account:hover { color: var(--ui-primary); }
.nav-order { align-items: center; gap: var(--ui-space-1); min-height: 44px; color: var(--ui-white); font-size: 14px; font-weight: 400; white-space: nowrap; text-underline-offset: 3px; }
.nav-order-type { text-decoration: underline; }
.nav-order-store { text-decoration: underline; }
/* The bucket: KFC's Bucket Device in white on the black bar, the count set into it in black. */
.header-bucket, .cart-bucket { position: relative; display: inline-flex; align-items: center; justify-content: center; }
.header-bucket { width: var(--w-tap-inline); height: var(--w-tap-inline); color: var(--ui-white); text-decoration: none; }
/* Phone: the cart is the red bar at the foot, so the bar up here holds only the lettermark and
   START ORDER (mobile-plp-and-story). */
.nav-account, .header-bucket { display: none; }
/* Once ordering has started, the order's pickup/delivery + restaurant takes START ORDER's place at
   every width (QA E09: on a phone it used to vanish, leaving only the lettermark). */
.nav-order { display: inline-flex; min-width: 0; max-width: 60vw; }
.nav-order-store { overflow: hidden; text-overflow: ellipsis; }
.header-bucket .xicon { width: 32px; height: 25px; }
.bucket-n { position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-40%); text-align: center;
    font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; font-size: 13px; line-height: 1; color: var(--ui-black); }
.header-bucket:hover, .header-bucket[aria-current="page"] { color: var(--ui-primary); }
/* The Cart expressive animation (ui-motion 15, MEASURED ~870ms): an item drops into the bucket,
   the bucket tips and bounces, the count rolls up. motion.js adds .is-dropping on every add. */
@keyframes kfc-bucket { 0%, 30% { transform: none; } 45% { transform: rotate(-8deg) translateY(2px); } 60% { transform: rotate(4deg) translateY(-3px); } 75% { transform: rotate(-2deg); } 100% { transform: none; } }
@keyframes kfc-drop { 0% { transform: translate(-10px, -26px) scale(.6); opacity: 0; } 15% { opacity: 1; } 40% { transform: translate(0, -2px) scale(.5); opacity: 1; } 45%, 100% { transform: translate(0, 4px) scale(.3); opacity: 0; } }
@keyframes kfc-roll { 0%, 40% { transform: translateY(-40%); opacity: 1; } 55% { transform: translateY(-110%); opacity: 0; } 56% { transform: translateY(40%); opacity: 0; } 100% { transform: translateY(-40%); opacity: 1; } }
.motion-ok .is-dropping .xicon-bucket { animation: kfc-bucket 870ms var(--ui-ease-out); transform-origin: 50% 100%; }
.motion-ok .is-dropping .bucket-n { animation: kfc-roll 870ms var(--ui-ease-standard); }
.motion-ok .is-dropping::before { content: ""; position: absolute; inset: 0; width: 12px; height: 12px; margin: auto;
    background: currentColor; animation: kfc-drop 870ms var(--ui-ease-in) both; }
.header-bucket:hover .bucket-n, .header-bucket[aria-current="page"] .bucket-n { color: var(--ui-white); }
/* START ORDER: the primary button, compact in the bar. m1: 44px, the WCAG 2.5.8 minimum.
   Review #39: white on Brand Red is 4.27:1, AA only as large text, so the label stays at the
   CTA size (19px Heavy) instead of shrinking to 16px in the bar. */
.site-header .btn { min-height: 44px; padding: 0 var(--ui-space-4); font-size: var(--ui-cta-size); }
@media (min-width: 600px) {
    .header-bucket { display: inline-flex; }
}
@media (min-width: 900px) {
    .site-nav { display: flex; align-items: center; gap: var(--ui-space-2); margin-left: var(--ui-space-6); }
    .nav-account { display: inline-flex; }
    .nav-order { max-width: none; }
}

/* ------------------------------------------------------------------ phone tab bar (<600px)
   KFC's app bar (mobile-cart-bar-and-tabbar, ui-motion 17): black, four items, an expressive icon
   over a Sans label, white — the current one Brand Red. Fixed to the foot of the screen; the page
   keeps room for it, and the red cart bar sits on top of it. */
:root { --tab-h: 64px; }
.tab-bar { display: none; }
.xicon { display: block; width: 28px; height: 28px; }
.xi-burst { opacity: 0; }
@media (max-width: 599px) {
    body:has(> .tab-bar) { padding-bottom: calc(var(--tab-h) + env(safe-area-inset-bottom)); }
    .tab-bar {
        position: fixed; left: 0; right: 0; bottom: 0; z-index: 26; display: grid; grid-template-columns: repeat(4, 1fr);
        height: calc(var(--tab-h) + env(safe-area-inset-bottom)); padding-bottom: env(safe-area-inset-bottom);
        background: var(--ui-black); color: var(--ui-white); border-radius: var(--ui-radius-none);
    }
    .tab { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--ui-space-1); min-height: var(--tab-h);
        color: var(--ui-white); text-decoration: none; font-size: 12px; line-height: 16px; font-weight: 300; cursor: pointer; list-style: none; }
    .tab[aria-current="page"], .nav-menu[open] > .tab { color: var(--ui-primary); }
}
/* The expressive icons' own motion (ui-motion 13-16, MEASURED), played once by the CURRENT tab
   as its page opens, and again on a press: Home - the awning ripples; Menu - the box lid lifts and
   tilts about -5deg (370ms); Rewards - the heart turns red with a burst (800ms). Transform and
   opacity only; nothing with reduced motion. */
@keyframes kfc-awning { 0%, 100% { transform: none; } 40% { transform: scaleY(.82) translateY(-1px); } 70% { transform: scaleY(1.06); } }
@keyframes kfc-lid { 0%, 100% { transform: none; } 45% { transform: translateY(-3px) rotate(-5deg); } }
@keyframes kfc-burst { 0% { opacity: 0; transform: scale(.4); } 35% { opacity: 1; } 100% { opacity: 0; transform: scale(1.35); } }
@keyframes kfc-beat { 0%, 100% { transform: none; } 30% { transform: scale(1.12); } }
.xi-awning, .xi-lid, .xi-burst, .xi-heart { transform-box: fill-box; transform-origin: 50% 100%; }
.xi-lid { transform-origin: 10% 100%; }
.xi-burst { transform-origin: 50% 60%; }
.motion-ok .tab[aria-current="page"] .xi-awning, .motion-ok .tab:active .xi-awning { animation: kfc-awning 400ms var(--ui-ease-out); }
.motion-ok .tab[aria-current="page"] .xi-lid, .motion-ok .tab:active .xi-lid { animation: kfc-lid 370ms var(--ui-ease-out); }
.motion-ok .tab[aria-current="page"] .xi-burst, .motion-ok .tab:active .xi-burst { animation: kfc-burst 800ms var(--ui-ease-out); fill: var(--ui-accent-2); }
.motion-ok .tab[aria-current="page"] .xi-heart, .motion-ok .tab:active .xi-heart { animation: kfc-beat 800ms var(--ui-ease-out); }

/* Phone menu, opened from the tab bar's More: a black sheet docked above the bar (dialog radius
   16, top corners only, stated). Items are 56px tall (over the 44px minimum), Serif Heavy Italic
   caps as in KFC's own digital-guidelines navigation, a Grey 700 rule between them. z-index 24 sits
   under the sticky cart bar (25), which hides while the menu is open. */
.nav-menu { display: contents; }
.nav-menu-button::-webkit-details-marker { display: none; }
.nav-menu-button::marker { content: ""; }
.nav-menu-panel { position: fixed; left: 0; right: 0; bottom: calc(var(--tab-h) + env(safe-area-inset-bottom)); z-index: 24; background: var(--ui-black);
    border-radius: var(--ui-radius-200) var(--ui-radius-200) 0 0; max-height: calc(100dvh - var(--tab-h) - 64px); overflow-y: auto; }
.nav-menu-panel ul { list-style: none; margin: 0; padding: var(--ui-space-2) var(--ui-grid-margin) var(--w-gap-block); }
.nav-menu-panel li + li { border-top: var(--ui-border-100) solid var(--ui-grey-700); }
.nav-menu-panel a { display: flex; align-items: center; min-height: 56px; color: var(--ui-white); text-decoration: none;
    font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 20px; line-height: 24px; }
.nav-menu-panel a[aria-current="page"], .nav-menu-panel a:focus-visible { color: var(--ui-primary); }
@media (hover: hover) { .nav-menu-panel a:hover { color: var(--ui-primary); } }
body:has(.nav-menu[open]) .cart-bar { visibility: hidden; }
@media (min-width: 600px) { .nav-menu { display: none; } }

/* ------------------------------------------------------------------ buttons
   Primary: Brand Red fill, white Serif Heavy Italic caps at 19px (large text, see --ui-cta-size),
   radius 4. Press: scale .97 + label roll (MEASURED from KFC's button video). */
.btn {
    position: relative; overflow: hidden;
    display: inline-flex; align-items: center; justify-content: center; gap: var(--ui-space-2);
    min-height: var(--tap); padding: 0 var(--ui-space-5);
    border: 0; border-radius: var(--ui-radius-40);
    background: var(--ui-cta-bg); color: var(--ui-cta-text);
    font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase;
    font-size: var(--ui-cta-size); line-height: 24px; letter-spacing: 0; text-decoration: none; cursor: pointer;
    transition: transform var(--ui-dur-press) var(--ui-ease-out), background-color var(--ui-dur-press) var(--ui-ease-out);
}
.btn:focus-visible { background: var(--ui-cta-bg-pressed); }
@media (hover: hover) { .btn:hover { background: var(--ui-cta-bg-pressed); } }
.btn:active { transform: scale(.968); background: var(--ui-cta-bg-pressed); }   /* MEASURED, ui-motion 01 */
.btn.btn[disabled], .btn.btn[aria-disabled="true"], fieldset:disabled .btn.btn {
    background: var(--ui-grey-100); color: var(--ui-grey-500); cursor: not-allowed; transform: none;
}
.btn-block { display: flex; width: 100%; }
/* A class selector beats the browser's own [hidden] rule, so .btn-block[hidden] stayed on screen.
   That is what kept the dead grey CONTINUE TO PAYMENT block visible after the payment step opened
   (B4) — the same trap already documented for .cart-bar[hidden] and .progress[hidden]. */
.btn[hidden], .btn-block[hidden] { display: none; }
.btn-large { min-height: 56px; }
/* Secondary: black outline on white, black label (21:1), KFC Button size 16px. */
.btn-outline {
    background: var(--ui-white); color: var(--ui-black); box-shadow: inset 0 0 0 1px var(--ui-black); font-size: 16px;
}
.btn-outline:focus-visible, .btn-outline:active { background: var(--ui-grey-100); color: var(--ui-black); }
@media (hover: hover) { .btn-outline:hover { background: var(--ui-grey-100); color: var(--ui-black); } }
.btn-count {
    display: inline-block; min-width: 24px; padding: 0 var(--ui-space-1); border-radius: var(--ui-radius-40); background: var(--ui-white); color: var(--ui-black);
    font-family: var(--ui-font-body); font-style: normal; font-weight: 400; font-size: 14px; line-height: 24px; text-align: center;
}

/* Label roll: motion.js wraps a text-only label in two stacked copies (the copy is aria-hidden). */
.btn-roll { display: inline-grid; overflow: hidden; line-height: inherit; }
.btn-roll > span { grid-area: 1 / 1; transition: transform var(--ui-dur-label-roll) var(--ui-ease-standard); }
.btn-roll > span + span { transform: translateY(110%); }
.btn:active .btn-roll > span:first-child { transform: translateY(-110%); }
.btn:active .btn-roll > span + span { transform: none; }
@media (hover: hover) {
    .btn:not([disabled]):not([aria-disabled="true"]):hover .btn-roll > span:first-child { transform: translateY(-110%); }
    .btn:not([disabled]):not([aria-disabled="true"]):hover .btn-roll > span + span { transform: none; }
}

.text-link { display: inline-flex; align-items: center; gap: var(--ui-space-1); min-height: var(--tap); color: var(--ui-text-link); font-weight: 400; text-underline-offset: 3px; }
.link-button {
    background: none; border: 0; padding: 0 var(--ui-space-1); min-height: var(--tap); cursor: pointer; font-weight: 400;
    color: var(--ui-text-link); text-decoration: underline; text-underline-offset: 3px; font-size: 14px;
}
/* M10 — spec §5, verbatim: functional icons are Black on light and "are never red in the
   functional set". The label stays Digital Red; only the glyph goes black. */
.text-link .icon, .link-button .icon, .store-current .change .icon, .locate-button .icon { color: var(--ui-black); }

/* ------------------------------------------------------------------ page frame */
main { display: block; }
/* The Stripes bands run off the right edge of the screen on purpose. `clip`, not `hidden`: it
   stops the page scrolling sideways without making <main> a scroll container, so the sticky
   category strip and cart bar keep working. */
main { overflow-x: clip; }
/* Mobile pages were vertically heavy and desktop ones compressed, so the frame is not one
   number: 20px above the first thing on a phone, the stated 32 from 600px up. */
.page { padding-top: var(--ui-space-5); padding-bottom: var(--ui-space-12); }
@media (min-width: 600px) { .page { padding-top: var(--ui-space-8); padding-bottom: var(--ui-space-14); } }
.page-head { margin-bottom: var(--ui-space-6); }
.page-head p { margin-top: var(--ui-space-3); }

.notice { border-radius: var(--ui-radius-100); padding: var(--ui-space-3) var(--ui-space-4); background: var(--ui-warning-light); color: var(--ui-black); margin: 0 0 var(--ui-space-4); }
.error-text { color: var(--ui-error-dark); font-weight: 400; }
[role="alert"]:empty { display: none; }

/* ------------------------------------------------------------------ THE HOME PAGE
 * kfc-aruba.com's brand home, rebuilt: hero slides, the order block, the menu row, the two
 * worlds, favourites, events, birthdays, careers, find your KFC. Bands alternate black / white /
 * grey / red the way KFC market sites do, every band on the page grid, no cards, no gradients.
 */

/* Hero (homepage-4-languages, video19): the headline ON the photo, top left, in white, with a
   small red ORDER NOW under it and KFC's dash pagination below — no panel, no gradient. KFC's
   hero photos are shot dark where the words go; a soft text shadow (not a box) keeps AA contrast
   on a lighter frame, and guidelines.cjs measures it. Homepage hero banner 2:1 (stated) from
   900px, capped so the order block still starts in the first screen; 4:5 on a phone, as KFC's
   mobile hero cards are. */
.home-hero { position: relative; background: var(--ui-black); color: var(--ui-white); }
.home-slides { list-style: none; margin: 0; padding: 0; }
.home-hero-many .home-slides { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; }
.home-hero-many .home-slides::-webkit-scrollbar { display: none; }
.home-hero-many .home-slide { flex: 0 0 100%; scroll-snap-align: start; }
.motion-ok .home-hero-many .home-slides { scroll-behavior: smooth; }
.home-slide { position: relative; }
.home-slide-img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; object-position: 60% 30%; background: var(--ui-grey-800); }
/* QA E11: the words never sit on the photograph. Over this campaign photo the subtitle measured
   ~2.0:1 and the red accent ~2.4:1, and no scrim short of blacking the picture out fixes a red
   word over a lit face. So the text sits on the hero's own black: below the photo on a phone
   and tablet, in a left column beside it from 900px (image on the right, cropped to fit). White
   on black is 21:1, Brand Red on black 4.9:1 (AA for the large accent and for body). */
.home-slide-text { position: static; padding: var(--w-gap-block) 0 var(--ui-space-8); }
.home-slide-panel { max-width: 640px; }
/* Overline (stated): Sans Regular 12/16 caps. */
.home-slide-text .kfc-overline { margin: 0 0 var(--ui-space-2); color: var(--ui-white); font-size: 12px; line-height: 16px; font-weight: 400; }
/* Serif H1 on a phone; Stripes Hero from 900px (Stripes is Mega and Hero sizes only, and a 72px
   Stripes word does not fit 358px). */
.home-slide-title { margin: 0; font-size: var(--t-h1); line-height: 1; color: var(--ui-white); max-width: 11ch; }
.home-slide-title span { display: block; }
.home-red { color: var(--ui-primary); }
.home-slide-sub { margin: var(--ui-space-3) 0 0; font-size: 16px; line-height: 24px; max-width: 34ch; }
/* Review #39: 19px, not 14px: a red CTA's white label passes AA only as large text. */
.home-slide .home-actions .btn { min-height: var(--w-tap-inline); padding: 0 var(--ui-space-4); font-size: var(--ui-cta-size); line-height: 20px; text-shadow: none; }
/* On a photo the secondary button is filled black: a see-through outline over a light part of
   the picture was unreadable. */
.home-slide .btn-outline-light { background: var(--ui-black); }
.home-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-3) var(--w-gap-inline); margin: var(--w-gap-block) 0 0; }
@media (max-width: 599px) { .home-slide-img { aspect-ratio: 4 / 3; } }
@media (min-width: 600px) { .home-slide-img { aspect-ratio: 16 / 9; } }
@media (min-width: 900px) {
    .home-slide { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: center; }
    .home-slide-img { grid-column: 2; grid-row: 1; aspect-ratio: 4 / 3; height: 100%; max-height: calc(100vh - 64px - 120px); min-height: 440px; }
    .home-slide-text { grid-column: 1; grid-row: 1; padding: var(--ui-space-8) 0; }
    .home-slide-text .wrap { max-width: none; padding-right: var(--w-gap-block); }
    .home-slide-title { font-family: var(--ui-font-display); font-style: normal; font-size: var(--t-hero); line-height: 68px; max-width: 9ch; }
}
.home-slide-nav { background: var(--ui-black); }
.home-slide-nav .wrap { display: flex; gap: var(--ui-space-2); padding-top: var(--ui-space-2); padding-bottom: var(--ui-space-3); }
/* Dash pagination (KFC's carousels): a white dash per slide, the current one Brand Red. The tap
   target stays 44px; the dash is drawn inside it. The slide number is read, not shown. */
.home-slide-nav a { position: relative; display: inline-flex; align-items: center; justify-content: center; min-width: var(--w-tap-inline); min-height: var(--w-tap-inline);
    color: transparent; text-decoration: none; }
.home-slide-nav a::after { position: absolute; left: 10px; top: 50%; }
.home-slide-nav a::after { content: ""; width: 24px; height: 3px; background: var(--ui-white); }
.home-slide-nav a[aria-current="true"]::after { background: var(--ui-primary); }

/* Buttons on black and on red. The CTA red on the brand red would vanish, so on red the primary
   button turns white with a black label; on black the secondary is a white outline. */
.btn-outline-light { background: transparent; color: var(--ui-white); box-shadow: inset 0 0 0 1px var(--ui-white); }
.btn-outline-light:focus-visible, .btn-outline-light:active { background: var(--ui-grey-800); }
@media (hover: hover) { .btn-outline-light:hover { background: var(--ui-grey-800); } }
.btn-light { background: var(--ui-white); color: var(--ui-black); }
.btn-light:focus-visible, .btn-light:active { background: var(--ui-grey-100); color: var(--ui-black); }
@media (hover: hover) { .btn-light:hover { background: var(--ui-grey-100); color: var(--ui-black); } }
.text-link-light { color: var(--ui-white); }

/* The order block on the home page: one grey band straight under the hero. No white gap and no
   second black rule above it — the hero's own black edge is the divider (Morris, 1850px shot). */
.home-order { background: var(--ui-grey-50); scroll-margin-top: 0; }
.home-order .order-setup { padding: 0; }
.home-order .order-block { margin: 0; padding: var(--w-gap-block) 0 0; background: transparent; border-top: 0; }
.home-order-go { margin: 0; padding: var(--w-gap-block) 0 var(--w-gap-section); }
@media (min-width: 600px) { .home-order .order-block { padding-top: var(--w-gap-section); } }

/* A home band: its heading and its one link on one line. */
.home-block { padding: var(--ui-space-12) 0 0; }
.home-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--ui-space-2) var(--w-gap-inline); margin-bottom: var(--w-gap-block); }
.home-head h2 { margin: 0; }
/* Under a Stripes band the band IS the heading; the row keeps only its one link. */
.home-head-link { justify-content: flex-start; margin: var(--ui-space-2) 0 var(--w-gap-inline); }

/* The menu: KFC's category tiles (mobile-category-tiles) - a two-column grid, the name top-left
   in Serif Heavy Italic caps, the cut-out under it, thin black rules between the tiles; the
   featured tile (the offers) in Herbs. From 1136 it is one row of eight. Radius 0 (tiles). */
.home-categories .stripes { margin-bottom: 0; }
.home-category-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr;
    border-top: var(--ui-border-100) solid var(--ui-black); border-left: var(--ui-border-100) solid var(--ui-black); }
.home-category-list li { border-right: var(--ui-border-100) solid var(--ui-black); border-bottom: var(--ui-border-100) solid var(--ui-black); }
.home-category-list a { display: flex; flex-direction: column; justify-content: space-between; gap: var(--ui-space-2); min-height: 150px; height: 100%;
    padding: var(--ui-space-3); text-decoration: none; color: var(--ui-black); border-radius: var(--ui-radius-none); }
.home-category-list img { width: 88px; height: 88px; object-fit: contain; align-self: center; order: 2; }
.home-category-list span { order: 1; font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 16px; line-height: 1; }
.home-category-featured a { background: var(--ui-accent-1); }
@media (hover: hover) { .home-category-list a:hover span { color: var(--ui-primary-text); } .home-category-featured a:hover span { color: var(--ui-black); } }
@media (min-width: 600px) { .home-category-list { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1136px) { .home-category-list { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); grid-auto-flow: column; } .home-category-list a { min-height: 180px; } }

/* The two worlds: two photos, side by side from 900, each with its words on black under it. */
.home-worlds { display: grid; margin-top: var(--ui-space-12); background: var(--ui-black); color: var(--ui-white); }
@media (min-width: 900px) { .home-worlds { grid-template-columns: 1fr 1fr; } }
.home-world { display: flex; flex-direction: column; }
.home-world img { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; }
.home-world-text { padding: var(--w-gap-block) var(--ui-grid-margin) var(--w-gap-section); }
.home-world-text .kfc-overline { margin: 0 0 var(--ui-space-2); color: var(--ui-grey-200); font-size: 14px; line-height: 20px; }
.home-world-text h2 { margin: 0 0 var(--ui-space-3); color: var(--ui-white); }
.home-world-text > p { max-width: 46ch; margin: 0 0 var(--w-gap-block); font-size: 16px; line-height: 24px; }
.home-world-text > p:last-child { margin: 0; }
@media (min-width: 1136px) { .home-world-text { padding: var(--w-gap-section) var(--ui-space-12) var(--ui-space-12); } }

/* Signed in (homepage-4-languages): "WELCOME BACK," in Serif caps with the name in Brand Red. */
.home-welcome { margin: 0; padding-top: var(--w-gap-inline); padding-bottom: var(--w-gap-inline); font-family: var(--ui-font-heading); font-style: italic;
    font-weight: 900; text-transform: uppercase; font-size: var(--t-h3); line-height: 1; }
.home-welcome span { display: block; color: var(--ui-primary); }

/* The statement block: the brand line huge in Serif Heavy Italic caps (H1 up to Hero size is the
   heading face, not Stripes: it is a sentence), the Original Recipe stamp beside it, and KFC's
   Colonel <-> Stripes lettermark loop. On a phone the loop sits under the words. */
.home-statement { padding: var(--ui-space-12) 0; }
.home-statement .wrap { display: grid; gap: var(--w-gap-block); align-items: center; }
.home-statement-text { position: relative; }
.home-statement-title { font-size: clamp(40px, calc(40px + 32 * var(--ui-fluid)), 72px); line-height: 1; max-width: 9ch; margin-bottom: var(--w-gap-inline); }
.home-stamp { width: clamp(96px, 18vw, 150px); height: auto; margin: 0 0 var(--w-gap-inline); }
.home-statement-motion { display: block; width: min(100%, 360px); margin: 0 auto; }
@media (min-width: 900px) {
    .home-statement .wrap { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: var(--ui-space-12); }
    .home-stamp { position: absolute; right: 0; top: 0; }
}

/* The Offers & Rewards band: black, entered through KFC's slanted wipe (transition_3: a black edge
   at the bucket's angle, drawn as a clip-path), the title in red Serif caps, a sideways row of 3:4
   cards. The row is scroll-snap; the card that is not the active one sits at 0.92 and grows to
   full size as it becomes active (ui-motion 06), which motion.js drives. */
.home-offers { margin-top: var(--ui-space-12); padding: calc(var(--ui-space-12) + 4vw) 0 var(--ui-space-12); background: var(--ui-black); color: var(--ui-white);
    clip-path: polygon(0 4vw, 100% 0, 100% 100%, 0 100%); }
.home-offers-title { color: var(--ui-primary); margin: 0; }
.home-offer-row { list-style: none; margin: var(--w-gap-block) calc(-1 * var(--ui-grid-margin)) 0; padding: 0 var(--ui-grid-margin); display: grid; grid-auto-flow: column;
    grid-auto-columns: min(72%, 280px); gap: var(--ui-grid-gutter); overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--ui-grid-margin); scrollbar-width: none; }
.home-offer-row::-webkit-scrollbar { display: none; }
.home-offer-row > li { scroll-snap-align: start; transform-origin: 50% 100%; }
.motion-ok .home-offer-row > li { transition: transform var(--ui-dur-card, 250ms) var(--ui-ease-out); }
.motion-ok .home-offer-row > li.is-near { transform: scale(.92); }
/* Peek (ui-motion 07): an idle row hints the next card, out a third of a card and back. */
@keyframes kfc-peek { 0%, 100% { translate: 0 0; } 50% { translate: -33% 0; } }
.motion-ok [data-carousel].is-peeking > li { animation: kfc-peek var(--ui-dur-peek) var(--ui-ease-standard); }
@media (min-width: 1136px) { .home-offer-row { grid-auto-columns: calc((100% - 2 * var(--ui-grid-margin) - 3 * var(--ui-grid-gutter)) / 4); } }
/* QA: at 1440 the last card (Join KFC Aruba Rewards) was cut by the screen edge mid-sentence. On a
   desktop the favourites are laid out whole on the grid, wrapping, never scrolled off the edge:
   five in a row when there are five, three when there are six, otherwise four. */
@media (min-width: 1136px) {
    .home-offer-row { grid-auto-flow: row; grid-auto-columns: auto; grid-template-columns: repeat(4, minmax(0, 1fr));
        overflow: visible; margin-left: 0; margin-right: 0; padding: 0; row-gap: var(--w-gap-section); }
    .home-offer-row:has(> li:nth-child(5)):not(:has(> li:nth-child(6))) { grid-template-columns: repeat(5, minmax(0, 1fr)); }
    .home-offer-row:has(> li:nth-child(6)):not(:has(> li:nth-child(7))) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .home-offer-row > li.is-near { transform: none; }
}
.home-offers .offer-title, .home-offers .offer-price, .home-offers .offer-window { color: var(--ui-white); }
.home-offers .offer-window { color: var(--ui-grey-200); }
.offer-rewards-card { height: 100%; justify-content: flex-end; padding: var(--w-gap-block); background: var(--ui-primary); aspect-ratio: 3 / 4; }
/* In the desktop grid the card fills its own cell; the 3:4 ratio on a row-height card made it
   wider than the column and pushed it off the screen (QA). */
@media (min-width: 1136px) { .offer-rewards-card { width: 100%; aspect-ratio: auto; } }
.offer-rewards-card .offer-title { font-size: var(--t-h3); -webkit-line-clamp: 4; line-clamp: 4; }
.offer-rewards-card .btn { align-self: flex-start; margin-top: var(--ui-space-2); }

/* Order again: the signed-in customer's own last orders, a row of plain cards on a rule. */
.home-again-title { margin: 0 0 var(--w-gap-inline); color: var(--ui-primary); }
.home-again-row { list-style: none; margin: 0; padding: var(--w-gap-inline) 0 0; display: grid; gap: var(--ui-grid-gutter); border-top: var(--ui-border-100) solid var(--ui-grey-200); }
@media (min-width: 600px) { .home-again-row { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1136px) { .home-again-row { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.home-again-row a { display: flex; flex-direction: column; gap: var(--ui-space-1); padding: var(--w-gap-inline); border: var(--ui-border-100) solid var(--ui-grey-200);
    border-radius: var(--ui-radius-100); text-decoration: none; color: var(--ui-text); }
.home-again-row a:hover { border-color: var(--ui-grey-900); }
.home-again-name { font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: var(--t-h5); line-height: 1; }
.home-again-meta { font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); }

/* Events: dated rows. Only what has not ended; with none, the band is not rendered. */
.home-events h2 { margin: 0 0 var(--w-gap-block); }
.home-event-list { list-style: none; margin: 0; padding: 0; border-top: var(--ui-border-400) solid var(--ui-black); }
.home-event-list li { padding: var(--w-gap-block) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.home-event-when { margin: 0 0 var(--ui-space-1); color: var(--ui-primary); font-size: 16px; line-height: 22px; }
.home-event-list h3 { margin: 0 0 var(--ui-space-3); }

/* Birthdays: the red band. Photo and words side by side from 900. */
.home-parties { margin-top: var(--ui-space-12); background: var(--ui-primary); color: var(--ui-white); }
.home-parties .wrap { display: grid; gap: 0; padding-left: 0; padding-right: 0; max-width: none; }
@media (min-width: 900px) { .home-parties .wrap { grid-template-columns: 1fr 1fr; align-items: stretch; } }
.home-parties img { display: block; width: 100%; height: 100%; min-height: 240px; aspect-ratio: 3 / 2; object-fit: cover; }
.home-parties-text { padding: var(--w-gap-block) var(--ui-grid-margin) var(--w-gap-section); }
@media (min-width: 1136px) { .home-parties-text { padding: var(--ui-space-12); } }
.home-parties-text .kfc-overline { margin: 0 0 var(--ui-space-2); font-size: 14px; line-height: 20px; }
.home-parties-text h2 { margin: 0 0 var(--ui-space-3); color: var(--ui-white); }
.home-parties-from { margin: 0 0 var(--ui-space-3); font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 24px; line-height: 1; }
.home-parties-text > p { max-width: 48ch; font-size: 16px; line-height: 24px; }
.home-parties-packages { list-style: none; margin: var(--w-gap-inline) 0 0; padding: 0; border-top: var(--ui-border-100) solid var(--ui-white); max-width: 480px; }
.home-parties-packages li { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: var(--w-gap-inline); padding: var(--ui-space-2) 0; border-bottom: var(--ui-border-100) solid var(--ui-white); font-size: 16px; line-height: 22px; }
.home-parties-packages strong { font-weight: 400; }

/* Careers: words only, on white, at the reading measure. */
.home-careers .kfc-overline { margin: 0 0 var(--ui-space-2); color: var(--ui-text-secondary); font-size: 14px; line-height: 20px; }
.home-careers h2 { margin: 0 0 var(--ui-space-3); max-width: 18ch; }
.home-careers .answer { max-width: 60ch; }

/* The cart bar is sticky at the foot of the screen. A jump to #order, or to anything, must not
   land under it (Morris's laptop screenshot). */
html:has(.cart-bar:not([hidden])) { scroll-padding-bottom: 96px; }
@media (max-width: 599px) { html { scroll-padding-bottom: calc(var(--tab-h) + 16px); } html:has(.cart-bar:not([hidden])) { scroll-padding-bottom: calc(var(--tab-h) + 88px); } }

/* ------------------------------------------------------------------ order setup (home)
   P1-4. A distinct, spacious ordering block rather than a row of outlined boxes: its own band
   on the page's own grey, a 4px black rule above it — KFC's primary section divider — a heading
   that says what it is for, and the kiosk's selected treatment on both answers. The band runs
   to the page edges on a phone by taking the grid margin back and paying it again as padding,
   so the block is a band and its contents still sit on the grid. */
.order-setup { padding: var(--w-gap-inline) 0 var(--ui-space-1); }
.order-block {
    margin: 0 calc(-1 * var(--ui-grid-margin));
    padding: var(--w-gap-block) var(--ui-grid-margin) var(--w-gap-block);
    background: var(--ui-grey-50); border-top: var(--ui-border-400) solid var(--ui-black);
}
.order-block-title { margin: 0 0 var(--w-gap-inline); }
.fulfilment { display: grid; grid-template-columns: 1fr 1fr; gap: var(--w-gap-tight); margin: 0; }
.fulfilment button {
    display: flex; align-items: center; justify-content: center; gap: var(--w-gap-tight);
    min-height: 56px; border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100);   /* a selectable card: 1px Grey 200 (stated); the mark carries the contrast */
    background: var(--ui-white); color: var(--ui-black); cursor: pointer;
    font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 16px;
}
/* Pickup / delivery is the website's version of the kiosk's eat-in / takeaway question, so it
   gets the kiosk's answer: red line, light red fill, a mark — not a black fill, which read as a
   toggle switch in a settings form rather than as a choice that had been made. */
.fulfilment button[aria-pressed="true"] {
    background: var(--w-chosen-fill); border-color: var(--w-chosen-line); border-width: var(--w-chosen-width); color: var(--ui-black);
}
@media (hover: hover) { .fulfilment button:not([disabled]):hover { border-color: var(--ui-grey-900); } }
.fulfilment button[disabled] { color: var(--ui-grey-500); background: var(--ui-grey-50); border-color: var(--ui-grey-200); cursor: not-allowed; }
.fulfilment button[disabled] .chosen-mark { border-color: var(--ui-grey-200); }

.store-picker > summary { list-style: none; cursor: pointer; }
.store-picker > summary::-webkit-details-marker { display: none; }
/* The current restaurant, as a row inside the block rather than a form field: white, its own
   boundary, and the same 8px radius every selectable card on the site uses. */
.store-current {
    display: flex; align-items: center; gap: var(--ui-space-3); margin-top: var(--w-gap-inline); min-height: 56px;
    padding: var(--w-gap-tight) var(--ui-space-3); background: var(--ui-white);
    border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100);
}
/* Below 600px the status drops to its own line under the restaurant's name rather than
   competing with it for the same row — the name is the thing being named and it was the thing
   that wrapped. */
@media (max-width: 599px) {
    .store-current { flex-wrap: wrap; row-gap: var(--ui-space-1); }
    .store-current .status { order: 3; flex-basis: 100%; margin-left: calc(var(--ui-icon-md) + var(--ui-space-3)); }
}
.store-current .icon { color: var(--ui-black); }
.store-current .store-text { flex: 1; min-width: 0; }
.store-current .store-label { font-size: 12px; color: var(--ui-text-secondary); display: block; line-height: 16px; }
.store-current strong { font-size: 16px; line-height: 20px; }
.store-current .change { display: inline-flex; align-items: center; gap: var(--ui-space-1); font-size: 14px; font-weight: 400; color: var(--ui-text-link); text-decoration: underline; text-underline-offset: 3px; }
/* m7: the picker had no collapse affordance once open — `.change` was hidden outright and the
   chevron never flipped. Same control, swapped label, rotated glyph. */
.store-current .change-close { display: none; }
.store-picker[open] .change-open { display: none; }
.store-picker[open] .change-close { display: inline; }
.store-picker[open] .change .icon { transform: rotate(180deg); }
.store-current .change .icon { transition: transform var(--ui-dur-press) var(--ui-ease-out); }
.status { font-size: 14px; font-weight: 400; white-space: nowrap; }
.status-open::before, .status-closed::before {
    content: ""; display: inline-block; width: 8px; height: 8px; margin-right: var(--w-gap-tight); vertical-align: 1px; border-radius: var(--ui-radius-none);
}
.status-open { color: var(--ui-success-dark); }
.status-open::before { background: var(--ui-success-main); }
.status-closed { color: var(--ui-text-secondary); }
.status-closed::before { background: transparent; border: 1.5px solid var(--ui-grey-500); }

/* Store tiles = selectable cards: radius 8, 1px Grey 200, selected 1px Grey 900 (+ inset for weight). */
.store-list { list-style: none; margin: var(--ui-space-3) 0 0; padding: 0; display: grid; gap: var(--ui-space-2); }
.store-list button {
    width: 100%; height: 100%; text-align: left; cursor: pointer; background: var(--ui-white);
    border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100); padding: var(--ui-space-3) var(--ui-space-4); min-height: 64px;
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--ui-space-1) var(--ui-space-3); align-items: start; align-content: start;
}
.store-list form { height: 100%; }
.store-list button:hover { border-color: var(--ui-grey-900); }
/* Same chosen treatment again. A 1px grey-900 hairline plus a 1px inset was the whole signal
   that this was the restaurant you were ordering from, which is what made a row of four of them
   read as an administrative form rather than as a choice. */
.store-list button[aria-pressed="true"] {
    border-color: var(--w-chosen-line); border-width: var(--w-chosen-width); background: var(--w-chosen-fill); box-shadow: none;
}
.store-list .store-name { font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 16px; line-height: 20px; }
.store-list .store-address { grid-column: 1; font-size: 12px; line-height: 16px; color: var(--ui-text-secondary); }
/* Whether it is open is its own line under the address, at every width. It used to be a
   right-hand cell below 1136px and a third line above it, so the same four tiles said the same
   thing in two different shapes depending on the window. */
.store-list .status { grid-column: 1; margin-top: var(--ui-space-1); }
.store-list .chosen-mark { grid-column: 2; grid-row: 1 / span 3; align-self: center; }
@media (min-width: 600px) { .store-list { grid-template-columns: 1fr 1fr; gap: var(--ui-grid-gutter); } }
@media (min-width: 1136px) { .store-list { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 600px) {
    .order-setup { padding-top: var(--w-gap-block); }
    .order-block { padding-top: var(--w-gap-section); padding-bottom: var(--w-gap-section); }
    .fulfilment { max-width: 420px; gap: var(--w-gap-inline); }
}

/* Nearest store (store-locate.js): one plain line + a text link, under the picker. */
/* m6: the message and the button that acts on it must stay adjacent. They used to sit at
   opposite ends of a 1136px row — ~1100px apart — because the line took all the free space. */
.store-locate { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--ui-space-3); margin-top: var(--w-gap-tight); }
/* The consequence of the choice, not part of making it: its own space, below the block. */
.order-setup > .notice { margin: var(--w-gap-inline) 0 0; }
.nearest-line { margin: 0; flex: 0 1 auto; max-width: 100%; font-size: 14px; line-height: 20px; }
.nearest-line[hidden] { display: none; }
.locate-button { display: inline-flex; align-items: center; gap: var(--ui-space-1); text-decoration: none; }
.locate-button span, .locate-button { text-underline-offset: 3px; }
.locate-button[hidden] { display: none; }
.deliver-to { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-2) var(--ui-space-3); margin-top: var(--ui-space-3); }
.deliver-to label { font-weight: 400; font-size: 14px; }
.deliver-to select { flex: 1 1 200px; width: auto; }
@media (min-width: 1136px) { .order-block .store-locate, .order-block .deliver-to { grid-column: 1 / -1; justify-content: flex-start; } }

.login-prompt { display: flex; align-items: center; gap: var(--ui-space-3); margin-top: var(--ui-space-3); font-size: 14px; line-height: 20px; }
.login-prompt p { margin: 0; flex: 1 1 0; min-width: 0; }
.login-prompt .btn { flex: none; min-height: 44px; }

@media (min-width: 1136px) {
    .order-block { display: grid; grid-template-columns: 420px 1fr; column-gap: var(--ui-space-12); row-gap: var(--w-gap-inline); align-items: center; }
    /* The picker's own header is a line of text, not a 1280px-wide bar with its status and its
       Close stranded at opposite ends of the window (the m6 failure, in a different control). */
    .order-block .store-picker > summary { max-width: 720px; }
    .order-block-title { grid-column: 1 / -1; grid-row: 1; margin-bottom: 0; }
    .order-block .fulfilment { grid-column: 1; grid-row: 2; }
    .order-block .login-prompt { grid-column: 2; grid-row: 2; margin-top: 0; justify-content: flex-end; }
    .order-block .login-prompt p { flex: 0 1 auto; }
    .order-block .store-picker { grid-column: 1 / -1; }
    .order-setup .notice { margin-top: var(--ui-space-4); }
    /* m7: the summary STAYS. menu.js force-opens the picker at >=1100px, so hiding an open
       summary here took away both the Close control and the line naming the restaurant, on
       exactly the screens where the picker is always open. */
    .store-picker[open] .store-list { margin-top: var(--ui-space-5); }
}

.context-line { display: flex; align-items: center; gap: var(--ui-space-3); flex-wrap: wrap; padding: var(--ui-space-3) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); font-size: 14px; }
.context-line .spacer { flex: 1; }

/* ------------------------------------------------------------------ menu: category strip (sticky) */
.menu-head { padding: var(--ui-space-6) 0 var(--ui-space-2); }
/* KFC's PLP puts search at the top right of the listing (plp-desktop-final). */
@media (min-width: 1136px) { .menu-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--w-gap-block); } .menu-head .menu-search { margin-top: 0; } }
.category-strip { position: sticky; top: var(--header-h); z-index: 20; background: var(--ui-white); border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.category-strip ul {
    list-style: none; margin: 0 auto; padding: var(--ui-space-2) var(--ui-grid-margin); max-width: var(--ui-page-max);
    display: flex; gap: var(--ui-space-1); overflow-x: auto; scrollbar-width: none; scroll-snap-type: x proximity;
    /* M8: without this, scroll-snap-align: start snaps the first tile PAST the ul's own padding
       on load, so it sits flush to the viewport edge while everything else on the page starts at
       the 16px grid margin. */
    scroll-padding-left: var(--ui-grid-margin);
}
.category-strip ul::-webkit-scrollbar { display: none; }
/* Eight categories on a strip that scrolls sideways, so the width is not scarce: 104px a tile
   and a label at 13px, with two lines RESERVED, rather than eight names squeezed into 92px of
   12px type with some tiles a line taller than their neighbours. */
.category-strip a {
    display: flex; flex-direction: column; align-items: center; gap: var(--ui-space-1); width: 104px; min-height: var(--tap);
    padding: var(--ui-space-1) var(--ui-space-1) var(--ui-space-2); text-decoration: none; text-align: center; scroll-snap-align: start;
    border-bottom: var(--ui-border-300) solid transparent; border-radius: 0;
}
/* Category switch: the active rule and label cross over rather than snapping, so the strip
   confirms which section you are in while you scroll past it. */
.motion-ok .category-strip a { transition: border-bottom-color var(--ui-dur-title-line) var(--ui-ease-out); }
.motion-ok .category-strip span { transition: color var(--ui-dur-title-line) var(--ui-ease-out); }
.category-strip img { width: 56px; height: 56px; object-fit: contain; }
/* Overline style (Sans Regular 12 caps). Active = Digital Red + underline (KFC PLP tabs). */
.category-strip span { font-size: 13px; font-weight: 400; text-transform: uppercase; line-height: 16px; min-height: 32px; }
.category-strip a[aria-current="true"] { border-bottom-color: var(--ui-primary-text); }
.category-strip a[aria-current="true"] span, .category-strip a:hover span { color: var(--ui-primary-text); }
/* KFC's mobile PLP (mobile-plp, video 20): the strip is TEXT tabs - Sans, the current one in
   Digital Red with its underline, synced to the scroll. The photo tiles stay in the markup for
   the rail's no-JS fallback and are simply not shown. */
.category-strip ul { padding-top: 0; padding-bottom: 0; gap: var(--w-gap-inline); }
.category-strip a { width: auto; flex-direction: row; min-height: var(--w-tap-inline); padding: 0 0 2px; white-space: nowrap; }   /* hairline: label to its 3px active rule; --ui-strip-h counts it */
.category-strip img { display: none; }
.category-strip span { min-height: 0; font-size: 16px; line-height: 24px; font-weight: 400; text-transform: none; }

/* The PLP from 1136px, as kfc-aruba.com's own menu draws it (Morris, 2026-09-23): the categories
   are a ROW of photo tiles across the full width - the category's packshot over its name in Sans
   caps - under the MENU title, sticky under the header; the listing runs full width below it,
   four products to a row. Scrolled, the bar shrinks its photos so it does not eat the screen. The
   same <nav> is the text tabs below 1136px, so the scroll-spy in menu.js drives both. */
@media (min-width: 1136px) {
    .plp, .wrap-plp { max-width: none; padding-left: var(--ui-space-9); padding-right: var(--ui-space-9); }
    .plp { margin: 0 auto; }
    .plp > .category-strip { top: var(--header-h); margin: 0 calc(var(--ui-space-9) * -1); padding: 0 var(--ui-space-9);
        background: var(--ui-white); border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
    .plp > .category-strip ul { display: flex; justify-content: space-between; gap: var(--ui-space-4); padding: var(--ui-space-4) 0 0; overflow: visible; max-width: none; }
    .plp > .category-strip li { flex: 1 1 0; min-width: 0; }
    .plp > .category-strip a { display: flex; flex-direction: column; align-items: center; gap: var(--ui-space-3); width: auto; min-height: 0;
        padding: 0 0 var(--ui-space-3); text-align: center; white-space: normal; border-bottom: var(--ui-border-300) solid transparent; }
    .plp > .category-strip img { display: block; width: 120px; height: 120px; object-fit: contain; }
    .plp > .category-strip span { min-height: 40px; font-size: 16px; line-height: 20px; font-weight: 400; text-transform: uppercase; color: var(--ui-black); }
    .plp > .category-strip a[aria-current="true"] span, .plp > .category-strip a:hover span { color: var(--ui-primary-text); }
    .motion-ok .plp > .category-strip img { transition: width var(--ui-dur-title-line) var(--ui-ease-out), height var(--ui-dur-title-line) var(--ui-ease-out); }
    /* Stuck under the header: the same row, photos at half size, one line of name. */
    .plp > .category-strip.is-stuck ul { padding-top: var(--ui-space-2); }
    .plp > .category-strip.is-stuck img { width: 56px; height: 56px; }
    .plp > .category-strip.is-stuck span { min-height: 20px; font-size: 14px; }
    .plp > .plp-main { max-width: none; margin: 0; padding: 0; }
    .plp .menu-section { scroll-margin-top: calc(var(--header-h) + 120px); }
}

/* m2: the offset is the MEASURED sticky strip height, published as a token, plus a gap.
   It was 96/120 against a strip of 122/138, so a #category-N deep link landed under it. */
.menu-section { padding: var(--ui-space-8) 0 var(--ui-space-2); scroll-margin-top: calc(var(--header-h) + var(--ui-strip-h) + var(--ui-space-2)); }
@media (min-width: 600px) { .menu-section { padding-top: var(--ui-space-14); } }
.menu-section .category-title { margin-bottom: var(--ui-space-5); }

/* M12: the home page's closing block. Where the restaurants are, whether they are open, and a
   number to call — not a decorative photo pair under a slogan. Plain rows on a rule, no cards. */
.restaurants { padding: var(--ui-space-12) 0 var(--ui-space-8); }
.restaurants .answer { margin: 0; }
.restaurant-list { list-style: none; margin: var(--ui-space-6) 0 var(--ui-space-5); padding: 0;
    display: grid; gap: var(--ui-space-6); border-top: var(--ui-border-400) solid var(--ui-black); padding-top: var(--ui-space-5); }
@media (min-width: 600px) { .restaurant-list { grid-template-columns: 1fr 1fr; column-gap: var(--ui-grid-gutter); } }
@media (min-width: 1136px) { .restaurant-list { grid-template-columns: repeat(4, 1fr); } }
.restaurant-list li > * { margin: 0 0 var(--ui-space-1); }
.restaurant-list h3 a { text-decoration: none; }
.restaurant-list h3 a:hover { color: var(--ui-primary); }
.restaurant-address { font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); }

/* An answer block: one self-contained sentence, sized to be read first. It is what a model
   quotes, so it never depends on a heading or a table cell next to it for its meaning. */
.answer { font-size: 18px; line-height: 24px; max-width: 62ch; }
@media (min-width: 1136px) { .answer { font-size: 20px; line-height: 1.5; } }

/* ------------------------------------------------------------------ informational pages */
/* P1-5. Four desktop columns gave each restaurant ~300px, which wrapped KFC ORANJESTAD onto two
   lines, broke a three-clause opening-hours sentence over three, and left the addresses, the
   phone numbers and the statuses at four different heights. Two columns at every width above a
   phone, with a real card boundary so it is obvious which facts belong to which restaurant. */
.location-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--w-gap-block);
    border-top: var(--ui-border-400) solid var(--ui-black); padding-top: var(--w-gap-block); }
@media (min-width: 600px) { .location-list { grid-template-columns: 1fr 1fr; gap: var(--w-gap-block) var(--ui-grid-gutter); } }
/* The CTA is pushed to the bottom so they line up however many lines the addresses take. */
.location-list li { display: flex; flex-direction: column;
    border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-none);
    padding: var(--w-gap-inline); }
@media (min-width: 600px) { .location-list li { padding: var(--w-gap-block); } }
.location-list li > * { margin: 0 0 var(--w-gap-tight); }
/* Below 600px the card is the full width of a phone and the name still has to fit on one line,
   so the status drops beneath it rather than taking 85px off the side of the heading — the same
   rule the home page's restaurant row follows. */
.location-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--ui-space-1) var(--ui-space-3); }
.location-head .status { flex-basis: 100%; }
@media (min-width: 1136px) { .location-head .status { flex-basis: auto; } }
.location-head h2 { margin: 0; overflow-wrap: anywhere; }
.location-list h2 a { text-decoration: none; }
.location-list h2 a:hover { color: var(--ui-primary); }
.location-address, .location-hours { font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); }
/* Specific enough to beat `.location-list li > *`, which resets every margin in the column. */
.location-list li > .location-order { margin-top: auto; padding-top: var(--w-gap-inline); margin-bottom: 0; }

.fact-list { margin: var(--ui-space-6) 0 var(--ui-space-8); border-top: var(--ui-border-400) solid var(--ui-black); }
.fact-list > div { display: grid; grid-template-columns: 1fr; gap: var(--ui-space-1); padding: var(--ui-space-3) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
@media (min-width: 600px) { .fact-list > div { grid-template-columns: 180px minmax(0, 1fr); gap: var(--ui-space-4); } }
.fact-list dt { font-weight: 400; font-size: 14px; color: var(--ui-text-secondary); }
.fact-list dd { margin: 0; }

.qa section { padding: var(--ui-space-6) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.qa section:first-child { border-top: var(--ui-border-400) solid var(--ui-black); }
.qa h2 { margin-bottom: var(--ui-space-3); }
.qa .answer { margin: 0; }
.updated { margin-top: var(--ui-space-8); }

/* ------------------------------------------------------------------ THE CONTENT PAGES
 *
 * Our Flavours, Our Story, Our Values, Contact, Allergens, Deals, Kids parties, Events and
 * catering, Careers and the legal stubs. The same design system the rest of the website uses —
 * there is no third one here. Every value below is a token from the block at the top of this
 * file, and every NEW rule is a layout a page needs and the shop did not.
 *
 * What is deliberately NOT here, because a content page is where it creeps in:
 *   - no eyebrow label above a heading
 *   - no pill badge
 *   - no icon in a circle
 *   - no gradient
 *   - no three-up row of feature cards (the values page stacks, like the FAQ)
 * A card row would make eight flavour families read as eight products, which is the loudest
 * "this page was generated" signal a content page can send.
 */

/* Long-form copy out of the CMS. The measure is the same 62ch the answer block uses: prose wider
   than that loses the line, and this is the only place on the site with real paragraphs. */
.prose { max-width: 62ch; }
.prose > :last-child { margin-bottom: 0; }
.prose p { margin: 0 0 var(--ui-space-4); }
.prose h2 { margin: var(--w-gap-section) 0 var(--ui-space-3); }
.prose h3, .prose h4 { margin: var(--ui-space-6) 0 var(--ui-space-2); }
.prose ul, .prose ol { margin: 0 0 var(--ui-space-4); padding-left: var(--ui-space-5); }
.prose li { margin-bottom: var(--ui-space-2); }
.prose a { color: var(--ui-text-link); text-underline-offset: 3px; }
.prose blockquote { margin: var(--ui-space-6) 0; padding-left: var(--ui-space-4);
    border-left: var(--ui-border-300) solid var(--ui-primary); font-size: 18px; line-height: 24px; }
.prose hr { border: 0; border-top: var(--ui-border-100) solid var(--ui-grey-200); margin: var(--w-gap-section) 0; }
.prose-block { margin-top: var(--w-gap-section); }

/* A hole in the content, marked as one. Deliberately not styled as an error and deliberately
   not hidden: the rule is that a missing fact is stated, in the page, where KFC will see it.
   It reuses .notice, so there is one "something needs your attention" treatment on the site. */
.editorial-gap { margin: var(--w-gap-block) 0; max-width: 62ch; }
.editorial-gap > :last-child { margin-bottom: 0; }
.editorial-gap-head { font-family: var(--ui-font-heading); font-weight: 900; font-style: italic;
    text-transform: uppercase; font-size: 16px; line-height: 20px; margin-bottom: var(--ui-space-2); }
.editorial-gap-do { font-size: 14px; line-height: 20px; }
.editorial-gap a { text-underline-offset: 3px; }
.legal-stub { margin-bottom: var(--w-gap-section); }

/* The ordering entry point at the foot of a content page. One primary action and one plain link
   — kfc.nl exits to another domain here; this site is one system, so it is an internal link. */
.order-entry { margin-top: var(--w-gap-section); padding-top: var(--w-gap-block);
    border-top: var(--ui-border-400) solid var(--ui-black); max-width: 62ch; }
.order-entry h2 { margin-bottom: var(--ui-space-3); }
.order-entry-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-3) var(--w-gap-inline); margin: var(--w-gap-inline) 0 0; }

/* Flavour families: sections with a rule, exactly as /faq draws a question.
   Our Flavours is the one content page that keeps the full grid, and at 1136+ it earns it with a
   left rail: the family name in its own column, the copy in the next. The first pass ran the
   copy at a 62ch measure under a full-width rule, which at 1440 read as a page missing its
   right-hand column — the rule ended 700px past the last word. */
.flavour-list { margin-top: var(--w-gap-block); }
.flavour-list .flavour { padding: var(--w-gap-block) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.flavour-list .flavour:first-child { border-top: var(--ui-border-400) solid var(--ui-black); }
.flavour-list h2 { margin-bottom: var(--ui-space-3); color: var(--ui-primary); }
@media (min-width: 1136px) {
    .flavour-list .flavour { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); column-gap: var(--ui-space-12); align-items: start; }
    .flavour-list h2 { margin-bottom: 0; }
    /* The body, the live item line and the menu link are one column; the name is the other. */
    .flavour-list .flavour > :not(h2) { grid-column: 2; }
    /* The lede above the list and the order entry below it sit in that same second column, so
       every rule on the page ends at the right edge. Left at a 62ch measure on the left, the
       order-entry rule stopped 700px short of the rules above it. */
    .flavour-offset { margin-left: calc((100% - var(--ui-space-12)) * 5 / 12 + var(--ui-space-12)); }
}
.flavour-items { font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); max-width: 62ch; margin-bottom: 0; }
.flavour-items-label { color: var(--ui-text); }
.flavour-link { margin: 0; }

/* The story timeline. A year, a heading, a paragraph. The rule runs down the left at every
   width: a centred alternating timeline is a desktop-only ornament that becomes a single column
   on a phone anyway, so it is one column everywhere and honest about it. */
.timeline-head { margin: var(--w-gap-section) 0 var(--w-gap-block); }
.timeline { list-style: none; margin: 0; padding: 0 0 0 var(--ui-space-5);
    border-left: var(--ui-border-300) solid var(--ui-grey-200); }
.timeline > li { position: relative; padding-bottom: var(--w-gap-section); }
.timeline > li:last-child { padding-bottom: 0; }
/* The marker sits ON the rule, drawn from the same 3px border, not an icon in a circle. */
.timeline > li::before { content: ""; position: absolute; left: calc(-1 * var(--ui-space-5) - 7px); top: 6px;
    width: 11px; height: 11px; background: var(--ui-primary); }
.timeline-year { font-family: var(--ui-font-body); font-weight: 400; font-size: 14px; line-height: 20px;
    letter-spacing: .04em; text-transform: uppercase; color: var(--ui-text-secondary); margin-bottom: var(--ui-space-1); }
.timeline h3 { margin-bottom: var(--ui-space-2); }
@media (min-width: 600px) { .timeline { padding-left: var(--ui-space-6); } .timeline > li::before { left: calc(-1 * var(--ui-space-6) - 7px); } }

/* Values: the FAQ's stacked sections, not three columns of prose. */
.pillars h2 { color: var(--ui-primary); }

/* Deals. A photograph, a name, one sentence, and when it ends — a list of real offers, not a
   card grid: three deals in a row of cards is a layout that looks wrong at two deals and at four. */
.deal-list { list-style: none; margin: var(--w-gap-block) 0 0; padding: 0; display: grid; gap: var(--w-gap-block);
    border-top: var(--ui-border-400) solid var(--ui-black); padding-top: var(--w-gap-block); }
.deal-list li { display: grid; gap: var(--w-gap-inline); align-items: start; }
@media (min-width: 600px) { .deal-list li:has(.deal-photo) { grid-template-columns: minmax(0, 280px) minmax(0, 1fr); } }
.deal-photo img { display: block; width: 100%; height: auto; aspect-ratio: var(--w-card-media); object-fit: cover; background: var(--ui-grey-50); }
.deal-text > * { margin-bottom: var(--ui-space-2); }
.deal-text > :last-child { margin-bottom: 0; }
.deal-list h2 a { text-decoration: none; }
.deal-list h2 a:hover { color: var(--ui-primary); }
.deal-summary { max-width: 62ch; }
.deal-hero { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; margin-bottom: var(--w-gap-block); background: var(--ui-grey-50); }

/* ---------- The pages ported from kfc-aruba.com: promotions, the landing pages, parties, careers,
   Cos ta Hot, legal. Same tokens, same rules: rows with a rule between them, never a card grid. */
.promo-group { margin-top: var(--w-gap-section); }
.promo-group > h2 { margin-bottom: var(--ui-space-2); }
.promo-group-line { margin: 0; color: var(--ui-text-secondary); }
.deal-list h3 { margin: 0; }
.deal-list h3 a { text-decoration: none; }
.deal-list h3 a:hover { color: var(--ui-primary); }
/* The photo column is narrower inside the reading measure than it was on a full-width page. */
@media (min-width: 600px) { .wrap.narrow .deal-list li:has(.deal-photo) { grid-template-columns: minmax(0, 160px) minmax(0, 1fr); } }
.wrap.narrow .deal-photo img { aspect-ratio: 1 / 1; }
/* "In digital, the price remains in black" (ui-bucket-device, stated): Sans Regular, black. */
.deal-more { margin: 0; }

/* A list of menu items, drawn from the LIVE menu: photo, name and contents, price on the right. */
.item-list { list-style: none; margin: var(--w-gap-inline) 0 0; padding: 0; border-top: var(--ui-border-400) solid var(--ui-black); }
.item-list li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--ui-space-1) var(--w-gap-inline); align-items: start;
    padding: var(--ui-space-4) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.item-list li:has(.item-list-photo) { grid-template-columns: 72px minmax(0, 1fr) auto; }
@media (min-width: 600px) { .item-list li:has(.item-list-photo) { grid-template-columns: 96px minmax(0, 1fr) auto; } }
.item-list-photo img { display: block; width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover; background: var(--ui-grey-50); }
.item-list h3 { margin: 0 0 var(--ui-space-1); font-size: 16px; line-height: 20px; }
.item-list h3 a { text-decoration: none; }
.item-list h3 a:hover { color: var(--ui-primary); text-decoration: underline; }
.item-list-text p { margin: 0; font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); }
.item-list-price { margin: 0; white-space: nowrap; }

/* The restaurants, from `stores`: never typed into a page. */
.store-facts { list-style: none; margin: var(--w-gap-inline) 0 0; padding: 0; border-top: var(--ui-border-400) solid var(--ui-black); }
.store-facts li { padding: var(--ui-space-4) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.store-facts h3 { margin: 0 0 var(--ui-space-1); font-size: 18px; line-height: 24px; }
.store-facts p { margin: 0; }
.store-facts a { text-underline-offset: 3px; }
.store-facts-hours { color: var(--ui-text-secondary); font-size: 14px; line-height: 20px; }

.landing-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-3) var(--w-gap-inline); margin: var(--w-gap-section) 0 0; }
.landing-faq { margin-top: var(--w-gap-section); }
.landing-faq > h2 { margin-bottom: var(--w-gap-inline); }
.landing-faq > h2 + section { border-top: var(--ui-border-400) solid var(--ui-black); }
.qa h3 { margin: 0 0 var(--ui-space-3); font-size: 18px; line-height: 24px; }
.landing-related { margin-top: var(--w-gap-section); }
.landing-related ul { margin: var(--ui-space-3) 0 0; padding-left: var(--ui-space-5); }
.landing-related li { margin-bottom: var(--ui-space-2); }
.landing-related a { color: var(--ui-text-link); text-underline-offset: 3px; }

/* Kids-party packages and job openings: stacked sections, each under a rule. */
.packages, .roles { border-top: var(--ui-border-400) solid var(--ui-black); margin-top: var(--w-gap-inline); }
.roles { margin-top: var(--w-gap-section); }
.roles > h2 { margin: var(--w-gap-block) 0 0; }
.package, .role { padding: var(--w-gap-block) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.package h3, .role h3 { margin: 0 0 var(--ui-space-1); }
.package-for, .role-where { margin: 0 0 var(--ui-space-2); color: var(--ui-text-secondary); font-size: 14px; line-height: 20px; }
.package-price { margin: 0 0 var(--ui-space-3); color: var(--ui-black); font-weight: 400; font-size: 20px; line-height: 24px; }
.package .prose p:last-child, .role .prose p:last-child { margin-bottom: 0; }

.episode-lead { margin-top: var(--w-gap-block); padding-top: var(--w-gap-block); border-top: var(--ui-border-400) solid var(--ui-black); }
.episode-lead h2 { margin-bottom: var(--ui-space-3); }
.episode-list { margin: var(--ui-space-3) 0 0; padding-left: var(--ui-space-5); }

/* Legal text: numbered sections read as a document, and the one table breaks out of the measure. */
.legal-text h2 { font-size: 22px; line-height: 1; }
.legal-text table { border-collapse: collapse; width: 100%; font-size: 14px; line-height: 20px; margin: var(--w-gap-inline) 0; }
.legal-text th, .legal-text td { padding: var(--ui-space-2) var(--ui-space-3) var(--ui-space-2) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); text-align: left; vertical-align: top; }
.legal-text th { border-bottom: var(--ui-border-400) solid var(--ui-black); }
/* Five columns do not fit 358px: the table scrolls inside itself, the page never does. */
@media (max-width: 599px) { .legal-text table { display: block; overflow-x: auto; } .legal-text th, .legal-text td { min-width: 140px; } }
.legal-nav { margin-top: var(--w-gap-section); padding-top: var(--w-gap-block); border-top: var(--ui-border-100) solid var(--ui-grey-200); }
.legal-nav h2 { font-size: 16px; line-height: 20px; margin-bottom: var(--ui-space-3); }
.legal-nav ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--ui-space-2) var(--w-gap-inline); }
.legal-nav a { text-underline-offset: 3px; }
.legal-nav a[aria-current="page"] { color: var(--ui-text); text-decoration: none; }

/* Allergens. The table is the page, so it gets the full grid and its own scroll container rather
   than being squeezed into the reading measure. */
.allergen-ask { margin-top: var(--w-gap-section); max-width: 62ch; }
.allergen-phones { margin: var(--ui-space-4) 0; padding: 0; list-style: none; }
.allergen-phones li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--ui-space-1) var(--w-gap-inline);
    padding: var(--ui-space-1) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-100); }
.allergen-phones-name { font-weight: 900; }
.allergen-phones a { min-height: 44px; display: inline-flex; align-items: center; }
.table-scroll { overflow-x: auto; margin: var(--w-gap-block) 0; }
/* The allergen table is the one thing on a content page that must be wider than the reading
   measure, so it breaks out of it instead of widening the page around it. Capped at the page
   grid, and it only ever applies once KFC Aruba has published a row. */
.wrap.narrow .table-scroll { width: min(100vw - 2 * var(--ui-grid-margin), var(--ui-page-max)); margin-left: 50%; transform: translateX(-50%); }
.allergen-table { border-collapse: collapse; width: 100%; font-size: 14px; line-height: 20px; }
.allergen-table caption { text-align: left; padding-bottom: var(--ui-space-3); color: var(--ui-text-secondary); }
.allergen-table th, .allergen-table td { padding: var(--ui-space-2) var(--ui-space-3); border-bottom: var(--ui-border-100) solid var(--ui-grey-200); text-align: left; }
.allergen-table thead th { border-bottom: var(--ui-border-300) solid var(--ui-black); vertical-align: bottom; font-weight: 400; }
.allergen-table tbody th { font-weight: 400; }
.allergen-table .allergen-cell { text-align: center; }
.allergen-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.allergen-col span { display: inline-block; max-width: 96px; }

/* Careers */
.apply { margin-top: var(--w-gap-section); padding-top: var(--w-gap-block); border-top: var(--ui-border-400) solid var(--ui-black); }
.apply h3 { margin: var(--w-gap-block) 0 var(--ui-space-3); }
.career-stores { margin: 0; padding: 0; list-style: none; }
.career-stores li { padding: var(--ui-space-2) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-100); font-size: 14px; line-height: 20px; }
.role-where { font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); }

/* ------------------------------------------------------------------ the contact form
 *
 * The branching is CSS, so it works with JavaScript off. `form:has(#kind-health:checked)`
 * opens the illness branch; with no :has support (or no CSS at all) every branch is visible and
 * the form still submits. Which is why no branch field is marked `required` in HTML: a hidden
 * required field is a form the browser refuses to submit and refuses to explain.
 */
.contact-form { max-width: 560px; margin-top: var(--w-gap-block); }
.contact-form legend h2 { margin: 0; }
.contact-form .hint { font-size: 12px; line-height: 16px; color: var(--ui-text-secondary); margin: var(--ui-space-1) 0 0; }
.contact-form fieldset.form-step + fieldset.form-step { padding-top: var(--w-gap-block); border-top: var(--ui-border-100) solid var(--ui-grey-200); }
.contact-form .optional { color: var(--ui-text-secondary); font-weight: 300; }
.contact-form .option-list { display: grid; gap: var(--ui-space-2); }
.contact-form .consent label { display: flex; align-items: flex-start; gap: var(--ui-space-3); font-weight: 300; cursor: pointer; }
.contact-form .consent input { margin-top: 2px; }   /* hairline: the 22px box on the 20px first line */
.contact-form button[type="submit"] { margin-top: var(--w-gap-inline); }
/* The honeypot. Off-screen rather than display:none, which some bots check for. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* The two branches. Hidden by default and opened by the answer above them — and because the
   selector needs :has, a browser without it shows both, which is the correct failure. */
@supports selector(:has(*)) {
    .contact-form .branch-complaint, .contact-form .branch-health { display: none; }
    .contact-form:has(#kind-complaint:checked) .branch-complaint,
    .contact-form:has(#kind-health:checked) .branch-complaint,
    .contact-form:has(#kind-health:checked) .branch-health { display: block; }
}

.contact-errors ul { margin: var(--ui-space-2) 0 0; padding-left: var(--ui-space-5); }
.contact-errors li { margin-bottom: var(--ui-space-1); }
.contact-sent { border: var(--w-chosen-width) solid var(--w-chosen-line); background: var(--w-chosen-fill);
    padding: var(--w-gap-inline); margin-bottom: var(--w-gap-block); border-radius: var(--ui-radius-100); }
@media (min-width: 600px) { .contact-sent { padding: var(--w-gap-block); } }
.contact-sent > :last-child { margin-bottom: 0; }
.contact-sent h2 { margin-bottom: var(--ui-space-3); }
.contact-reference { font-family: var(--ui-font-body); font-weight: 400; font-variant-numeric: tabular-nums; font-size: 18px; letter-spacing: .04em; }
.contact-other { margin-top: var(--w-gap-section); padding-top: var(--w-gap-block); border-top: var(--ui-border-400) solid var(--ui-black); max-width: 62ch; }
.contact-other h2 { margin-bottom: var(--ui-space-3); }

/* ------------------------------------------------------------------ footer (p5)
   Two bands. The top one is the real information — the NAP for all four restaurants and the head
   office. The bottom one is where everything is, in kfc-aruba.com's own groups: Explore, Popular
   searches, Nearby, and the pages about the company. The middle two are the only internal links
   the eight search landing pages have, so they are always shown, on every page. */
.site-footer { border-top: var(--ui-border-400) solid var(--ui-black); padding: var(--ui-space-8) 0 var(--ui-space-10); font-size: 14px; line-height: 20px; color: var(--ui-text); }
.footer-grid { display: grid; gap: var(--ui-space-8); }
@media (min-width: 900px) { .footer-grid { grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); column-gap: var(--ui-space-12); } }
.footer-office p { margin: 0 0 var(--ui-space-3); color: var(--ui-text-secondary); }
.footer-office a { color: var(--ui-text); text-underline-offset: 3px; }
.footer-social { display: flex; flex-wrap: wrap; gap: var(--ui-space-2) var(--ui-space-4); }
.footer-social a { text-underline-offset: 3px; }
/* Short link lists: two to a row on a phone (every label fits in half of 358px), four at 900. */
.footer-nav { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--ui-space-8) var(--ui-grid-gutter);
    margin-top: var(--ui-space-8); padding-top: var(--ui-space-8); border-top: var(--ui-border-100) solid var(--ui-grey-200); }
@media (min-width: 900px) { .footer-nav { grid-template-columns: repeat(4, minmax(0, 1fr)); column-gap: var(--ui-space-10); } }
.footer-links a { text-underline-offset: 3px; }
.footer-legal a { text-underline-offset: 3px; }
.footer-legal-sep { padding: 0 var(--ui-space-1); }
.site-footer h2 { font-size: 16px; line-height: 20px; margin: 0 0 var(--ui-space-4); }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.footer-stores ul { display: grid; gap: var(--ui-space-4); }
@media (min-width: 600px) { .footer-stores ul { grid-template-columns: 1fr 1fr; column-gap: var(--ui-grid-gutter); } }
.footer-stores li { display: flex; flex-direction: column; gap: var(--ui-space-1); }
.footer-stores span { color: var(--ui-text-secondary); }
.footer-stores a { text-underline-offset: 3px; }
.footer-hours { margin: var(--ui-space-4) 0 0; color: var(--ui-text-secondary); }
.footer-links li { margin-bottom: var(--ui-space-2); }
/* Review #38: the money steps' slim footer: the language switch on one line, then the legal line. */
.site-footer-slim .footer-language ul { display: flex; flex-wrap: wrap; column-gap: var(--ui-space-5); }
.footer-delivery { margin: var(--ui-space-4) 0 0; color: var(--ui-text-secondary); }
.footer-legal { margin: var(--ui-space-8) 0 0; padding-top: var(--ui-space-4); border-top: var(--ui-border-100) solid var(--ui-grey-200); font-size: 12px; line-height: 16px; color: var(--ui-text-secondary); }

/* Payment method chooser: KFC option cards, one per rail, side by side (the kiosk's payment choice
   in the site's own chosen treatment). White card, 1px Grey 200, radius 8 (selectable card), a
   Brand Red strip across the top; the provider's logo is shown as its owner draws it, never
   recoloured. The radio is visually hidden inside: the card is its label, so keyboard and screen
   readers get a real radio group. */
.pay-methods { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--ui-space-2); margin-bottom: var(--ui-space-6); }
.pay-method { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: var(--ui-space-1);
    min-height: var(--tap); padding: var(--ui-space-5) var(--ui-space-2) var(--ui-space-3); overflow: hidden;
    border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100);
    background: var(--ui-white); text-align: center; cursor: pointer; }
.pay-method::before { content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: var(--ui-primary); }
/* The one chosen treatment (see the design system), plus the focus ring the hidden radio cannot draw. */
.pay-method:has(input:checked) { border-color: var(--w-chosen-line); border-width: var(--w-chosen-width); background: var(--w-chosen-fill); }
.pay-method:has(input:focus-visible) { outline: 2px solid var(--ui-black); outline-offset: 2px; }
.pay-method-visual { display: flex; align-items: center; justify-content: center; width: 100%; height: 32px; }
.pay-method-visual img { display: block; max-width: 88%; max-height: 28px; width: auto; height: auto; }
.pay-method-visual svg { width: 28px; height: 28px; }
.pay-method-name { margin-top: var(--ui-space-1); font-size: 16px; line-height: 24px; font-weight: 400; text-transform: uppercase; letter-spacing: .04em; }
.pay-method-note { font-size: 12px; line-height: 16px; color: var(--ui-text-secondary); }
/* After a failure: the card that failed says so, in words and colour. */
.pay-method.is-failed .pay-method-note { color: var(--ui-error-dark); }
/* Not usable right now (RailAvailability): grey, no red strip, no pointer, and it says so. */
.pay-method.is-unavailable { cursor: not-allowed; background: var(--ui-grey-50); border-color: var(--ui-grey-200); }
.pay-method.is-unavailable::before { display: none; }
.pay-method.is-unavailable .pay-method-visual { filter: grayscale(1); opacity: .45; }
.pay-method.is-unavailable .pay-method-name { color: var(--ui-text-secondary); }
@media (max-width: 599px) { .pay-method.is-unavailable .pay-method-note { display: block; } }
@media (max-width: 599px) { .pay-method-note { display: none; } .pay-method.is-failed .pay-method-note { display: block; } }

/* How the last attempt ended (checkout.js outcome()), for every rail: the kiosk's outcome screen as
   a panel. Title in the error face, the server's words, Try again and an outlined Pay another way. */
.pay-outcome { margin: 0 0 var(--ui-space-6); padding: var(--ui-space-4); border: var(--ui-border-100) solid var(--ui-error-main);
    border-radius: var(--ui-radius-100); background: var(--ui-error-light); }
.pay-outcome[hidden] { display: none; }
.pay-outcome-title { margin: 0; font-size: 20px; line-height: 24px; color: var(--ui-error-dark); }
.pay-outcome-note { margin: var(--ui-space-2) 0 0; font-size: 16px; line-height: 24px; color: var(--ui-black); }
.pay-outcome-actions { display: flex; flex-wrap: wrap; gap: var(--ui-space-2); margin-top: var(--ui-space-4); }

/* The order page while the order waits for payment: the last attempt's outcome and the way to
   pay for this order again. Neutral while the customer is at their bank or in Pay.aw; the error
   set once it did not go through. */
.pay-state { margin: var(--ui-space-4) 0; padding: var(--ui-space-4); border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100); }
.pay-state[hidden] { display: none; }
.pay-state.is-failed { border-color: var(--ui-error-main); background: var(--ui-error-light); }
.pay-state-title { margin: 0; font-size: 20px; line-height: 24px; }
.pay-state.is-failed .pay-state-title { color: var(--ui-error-dark); }
.pay-state-note { margin: var(--ui-space-2) 0 0; font-size: 16px; line-height: 24px; }
.pay-state-actions { display: flex; flex-wrap: wrap; gap: var(--ui-space-2); margin-top: var(--ui-space-4); }
.pay-state-actions[hidden] { display: none; }
/* Sentoo `pending`: the bank is working on it. KFC's three stripes keep time; still when motion is off. */
.pay-state.is-processing { text-align: center; }
.stripe-loader { display: inline-flex; gap: var(--ui-space-2); height: 48px; margin-bottom: var(--ui-space-4); }
.stripe-loader i { display: block; width: 12px; background: var(--ui-primary); transform-origin: bottom; }
.motion-ok .stripe-loader i { animation: kfc-stripe-rise 1200ms var(--ui-ease-standard) infinite; }
.motion-ok .stripe-loader i:nth-child(2) { animation-delay: 150ms; }
.motion-ok .stripe-loader i:nth-child(3) { animation-delay: 300ms; }
@keyframes kfc-stripe-rise { 0%, 100% { transform: scaleY(0.35); } 50% { transform: none; } }

/* Guest checkout: the order link to keep, and the offer to save the details as an account. Same
   box as the pay state, neutral. */
.guest-order { margin: var(--ui-space-4) 0; padding: var(--ui-space-4); border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100); }
.guest-order h2 { margin: 0; font-size: 20px; line-height: 24px; }
.guest-order p { margin: var(--ui-space-2) 0 0; }
.guest-order .btn { margin-top: var(--ui-space-4); }
.guest-order-link { display: flex; flex-wrap: wrap; gap: var(--ui-space-2); margin-top: var(--ui-space-4); }
.guest-order-link input { flex: 1 1 220px; min-width: 0; }
.guest-order-link .btn { margin-top: 0; }
.checkout-signin { margin: 0 0 var(--ui-space-4); }

/* A payment that is live in another app (Pay.aw): a KFC payment state, the provider second. The
   logo small, the heading, the amount in black, the status, one outlined way out. */
.pay-live { display: flex; flex-direction: column; align-items: center; gap: var(--ui-space-2); margin: var(--ui-space-4) 0 0; padding: var(--ui-space-6) var(--ui-space-4);
    border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100); text-align: center; }
.pay-live[hidden] { display: none; }
.pay-live-logo { display: block; width: 120px; height: auto; }
.pay-live-title { margin: var(--ui-space-2) 0 0; font-size: 24px; line-height: 32px; color: var(--ui-primary); }
.pay-live-amount { margin: 0; font-family: var(--ui-font-heading); font-weight: 900; font-style: italic; font-size: 32px; line-height: 40px; }
.pay-live-status { margin: 0; font-size: 16px; line-height: 24px; color: var(--ui-text-secondary); }
.pay-live .btn-outline { margin-top: var(--ui-space-2); }

/* "Delivery by VapVap Eats": the rider brand, white-on-black only (the logo has no dark variant). */
.delivered-by { display: inline-flex; align-items: center; gap: 8px; background: var(--ui-black);
    color: var(--ui-white); padding: var(--ui-space-1) var(--ui-space-2); font-size: 12px; line-height: 16px; }
.delivered-by img { display: block; height: 18px; width: auto; }

/* Subcategory heading inside a category (Deliverect's full category hierarchy). */
/* Weight 400, not 700: Kentucky Fried Sans ships Light and Regular only and the body sets
   `font-synthesis-weight: none`, so 700 here rendered as Regular and the heading was carrying a
   weight it never had. The step up from the body is the size, the caps and the tracking. */
.subcategory-title { font-family: var(--ui-font-body); font-style: normal; font-weight: 400; font-size: 18px; line-height: 24px;
    text-transform: uppercase; letter-spacing: .01em; color: var(--ui-grey-800);
    margin: var(--ui-space-8) 0 var(--ui-space-4); }
@media (min-width: 600px) { .subcategory-title { font-size: 22px; } }
.menu-section .product-grid + .subcategory-title { margin-top: var(--ui-space-10); }

/* ------------------------------------------------------------------ product cards (radius 0; 8/8/4/12 stack, stated) */
.product-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--w-gap-block) var(--ui-grid-gutter); }
@media (min-width: 600px) { .product-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--w-gap-section) var(--ui-grid-gutter); } }
@media (min-width: 1136px) { .product-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.product { display: flex; flex-direction: column; height: 100%; border-radius: var(--ui-radius-none); }
/* One image container and one ratio for every product on the site (Menu item 4:3, stated), and
   the photograph LEFT-ALIGNED in it with the text under it: KFC ui-photography > Menu alignment,
   "scaled consistently across the PLP and left-aligned with the text". (It was centred for a
   while to match the kiosk; the guideline is explicit, and Morris asked for the guideline.)
   `contain`, never `cover`: a packshot is not shot to be cropped. */
.product-photo { aspect-ratio: var(--w-card-media); min-height: 0; overflow: hidden; background: var(--ui-white); display: flex; align-items: center; justify-content: flex-start; margin-bottom: var(--w-gap-tight); }
.product-photo img { width: 100%; height: 100%; object-fit: contain; object-position: left center; }
.product.is-sold-out .product-photo img { opacity: .45; filter: grayscale(1); }

/* Product tag (observed KFC pattern): Sans caps in Digital Red, 1px Digital Red outline, radius 4.
   Digital Red on white = 4.59:1, AA at 12px. min-height reserves the row on every card. */
.tags { display: flex; flex-wrap: wrap; gap: var(--ui-space-1); margin-bottom: var(--ui-space-2); min-height: 22px; }
.tag {
    display: inline-flex; align-items: center; border: var(--ui-border-100) solid var(--ui-primary-text); border-radius: var(--ui-radius-40);
    color: var(--ui-primary-text); font-size: 12px; font-weight: 400; text-transform: uppercase; line-height: 16px; padding: 0 var(--ui-space-1);
}
.tag-sold-out { border-color: var(--ui-grey-500); color: var(--ui-grey-500); }

/* The product name, as KFC's product card specifies it (product-card-spacing, plp-desktop-final):
   Serif Heavy Italic caps, up to THREE lines, the price straight under it. H5 on a phone, H4 from
   1136 (the mobile step is ASSUMED, see the typescale). Caps also flatten the POS's inconsistent
   casing ("COMBO #1 - 2 PC COMBO" vs "Combo #1 - 2 Pc Combo"), which is what the earlier sans
   Title Case was protecting against. Names are NOT height-reserved: KFC's own grid lets them run
   one to three lines and the CTA is pushed to the card's foot, so the actions still line up. A
   96-character POS name is clamped at three lines; the full name is on the product page. */
.product-name {
    font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase;
    font-size: var(--w-type-item); line-height: 1; letter-spacing: .25px; margin-bottom: var(--ui-space-2); overflow-wrap: anywhere;
    display: -webkit-box; -webkit-line-clamp: var(--w-card-name); -webkit-box-orient: vertical; overflow: hidden;
}
/* Price: Sans Regular, black (stated: "in digital, the price remains in black"). */
.product-price { font-family: var(--ui-font-body); font-style: normal; font-weight: 400; font-size: var(--w-type-money); line-height: 20px; margin: 0 0 var(--ui-space-1); }
/* Reserved as well: with only the name reserved, a one-line description still moved the price
   of the card beside it by a line. */
/* Card stack (stated, ui-layout-1 05): image, tag, 8, name, 8, price, 4, attributes, 12, CTA. */
.product-desc {
    font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); margin: 0 0 var(--ui-space-3);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    min-height: var(--w-card-desc);
}
.product .btn { margin-top: auto; padding: 0 var(--ui-space-2); }
@media (min-width: 1136px) { .product-desc { -webkit-line-clamp: 1; } }

/* ------------------------------------------------------------------ cart bar */
/* KFC's cart bar (mobile-cart-bar-and-tabbar): a Brand Red bar with a 4px radius (it is a button),
   the bucket carrying the item count, the total and CART > in the heading face, white on red at
   20px (large text: 4.27:1 passes). It rides the foot of the screen — on a phone on top of the tab
   bar — on a white strip so it never sits over a product photo edge to edge. The cart page's own
   checkout bar keeps the black band (it holds a real red button). */
.cart-bar {
    position: sticky; bottom: 0; z-index: 25; background: var(--ui-white); color: var(--ui-white);
    padding: var(--ui-space-2) var(--ui-grid-margin) calc(var(--ui-space-2) + env(safe-area-inset-bottom));
}
@media (max-width: 599px) { .cart-bar { bottom: calc(var(--tab-h) + env(safe-area-inset-bottom)); padding-bottom: var(--ui-space-2); } }
.cart-bar .wrap { padding: 0; display: flex; align-items: center; gap: var(--w-gap-inline); }
.cart-bar-link { flex: 1; display: flex; align-items: center; gap: var(--ui-space-3); min-height: 56px; padding: 0 var(--ui-space-4);
    border-radius: var(--ui-radius-40); background: var(--ui-cta-bg); color: var(--ui-white); text-decoration: none;
    font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 20px; line-height: 24px;
    transition: transform var(--ui-dur-press) var(--ui-ease-out), background-color var(--ui-dur-press) var(--ui-ease-out); }
.cart-bar-link:active { transform: scale(.968); background: var(--ui-cta-bg-pressed); }
@media (hover: hover) { .cart-bar-link:hover { background: var(--ui-cta-bg-pressed); } }
.cart-bar-link:focus-visible { outline-color: var(--ui-black); }
.cart-bucket { width: 32px; height: 32px; color: var(--ui-white); }
.cart-bucket .xicon { width: 30px; height: 23px; }
.cart-bucket .bucket-n { color: var(--ui-primary); font-size: 12px; }
.cart-bar-total { flex: 1; }
.cart-bar-go { display: inline-flex; align-items: center; gap: var(--ui-space-2); }
.cart-bar-checkout { background: var(--ui-black); padding-top: var(--w-gap-inline); padding-bottom: calc(var(--w-gap-inline) + env(safe-area-inset-bottom)); }
.cart-bar p { margin: 0; flex: 1; font-size: 16px; font-weight: 400; }
.cart-bar .btn { min-height: var(--w-tap-inline); }
/* The red bar is KFC's PHONE pattern only (mobile-cart-bar-and-tabbar). From 600px the cart is
   the header bucket and its count, which is where an add is shown (and said, #cart-live). */
@media (min-width: 600px) { .cart-bar:not(.cart-bar-checkout) { display: none !important; } }
.cart-bar[hidden] { display: none; }

/* ------------------------------------------------------------------ product sheet
   Dialog: radius 16 (stated); on phones docked to the bottom with top corners only. Open/close
   280ms (a sheet is lighter than KFC's measured 450ms full-page push). */
dialog.sheet {
    padding: 0; border: 0; margin: 0; width: 100%; max-width: 100%; max-height: 92vh; max-height: 92dvh;
    top: auto; bottom: 0; left: 0; right: 0; border-radius: var(--ui-radius-200) var(--ui-radius-200) 0 0;
    background: var(--ui-white); color: var(--ui-black); overflow: hidden;
}
dialog.sheet[open] { display: flex; flex-direction: column; }
dialog.sheet::backdrop { background: var(--ui-scrim); }
@media (min-width: 600px) {
    dialog.sheet { top: 50%; bottom: auto; left: 50%; right: auto; transform: translate(-50%, -50%); width: 560px; max-height: 88vh; border-radius: var(--ui-radius-200); }
}
.sheet-form { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin: 0; }
.sheet-body { overflow-y: auto; overflow-x: hidden; padding: 0 var(--ui-space-4) var(--ui-space-4); flex: 1 1 auto; min-height: 0; overscroll-behavior: contain; }
@media (min-width: 600px) { .sheet-body { padding: 0 var(--ui-space-6) var(--ui-space-4); } }

/* M11: a real bar above the scroll container, not a button floating over it. The close button
   used to be position: absolute, so the item name scrolled underneath it and was sliced in half
   by the dialog's overflow: hidden — the sheet's normal state, because a long option list means
   the customer is always scrolled. The bar carries its own copy of the name, which crosses in
   only once the big title has scrolled away, so the name is never on screen twice. */
.sheet-head { display: flex; align-items: center; gap: var(--ui-space-2); flex: none;
    padding: var(--ui-space-2) var(--ui-space-2) var(--ui-space-2) var(--ui-space-4); background: var(--ui-white); }
@media (min-width: 600px) { .sheet-head { padding-left: var(--ui-space-6); } }
.sheet-head-title {
    flex: 1; min-width: 0; margin: 0; opacity: 0;
    font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase;
    font-size: 16px; line-height: 20px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    transition: opacity var(--ui-dur-title-line) var(--ui-ease-out);
}
dialog.sheet.is-scrolled .sheet-head { border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
dialog.sheet.is-scrolled .sheet-head-title { opacity: 1; }
.sheet-close {
    flex: none; width: var(--tap); height: var(--tap);
    display: inline-flex; align-items: center; justify-content: center;
    border: 0; border-radius: var(--ui-radius-40); background: var(--ui-white); color: var(--ui-black); cursor: pointer; padding: 0;
}
/* p3: the photo sat left with an empty right half. Left-aligned is right for a CARD in a grid;
   a dialog is one object on its own, so it is centred and allowed the width. */
.sheet-photo { aspect-ratio: 4 / 3; max-height: 260px; width: 100%; display: flex; align-items: center; justify-content: center; margin: var(--ui-space-2) 0; }
.sheet-photo img { max-height: 100%; max-width: 100%; width: auto; object-fit: contain; }
.sheet-title { font-size: 28px; line-height: 1; margin: var(--ui-space-2) 0; }
.sheet-price { font-weight: 400; margin: 0 0 var(--ui-space-1); }
.sheet-desc { color: var(--ui-text-secondary); font-size: 14px; line-height: 24px; }
.sheet-loading { padding: var(--ui-space-16) 0; text-align: center; color: var(--ui-text-secondary); }

.group { border: 0; padding: 0; margin: var(--ui-space-5) 0 0; min-width: 0; }
/* m4: flex-wrap + margin-left:auto dropped REQUIRED onto its own line, right-aligned under
   "Choose 1", on every group whose name is long — which looks accidental. Three columns: the
   name takes what is left and wraps inside its own cell, and the rule and the badge stay put. */
.group legend { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: baseline; column-gap: var(--ui-space-3); width: 100%; padding: 0 0 var(--ui-space-2); border-bottom: var(--ui-border-300) solid var(--ui-black); }
.group-name { font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 20px; line-height: 20px; overflow-wrap: anywhere; }
.group-rule { font-size: 14px; color: var(--ui-text-secondary); white-space: nowrap; }
.group-required { font-size: 12px; line-height: 16px; font-weight: 400; text-transform: uppercase; color: var(--ui-black); white-space: nowrap; }
.group-required.is-met { color: var(--ui-text-secondary); }
.group.has-error legend { border-bottom-color: var(--ui-error-main); }
.group.has-error .group-required { color: var(--ui-error-dark); }
.group-error { margin: var(--ui-space-2) 0 0; color: var(--ui-error-dark); font-size: 14px; }
.group-error[hidden] { display: none; }
/* Review #7: the running count under the name, and an option that would go over the group's
   limit greyed out rather than refused after the tap. */
.group-count { grid-column: 1 / -1; font-size: 14px; color: var(--ui-text-secondary); }
.option label:has(input:disabled) { cursor: not-allowed; color: var(--ui-text-secondary); }
.options { list-style: none; margin: 0; padding: 0; }
/* Deliverect isUpsell groups: after the item's own questions, under their own red heading. */
.pdp-addons { margin-top: var(--ui-space-7); }
.pdp-addons-title { margin: 0; font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 24px; line-height: 24px; color: var(--ui-primary); }
.option-thumb { flex: none; width: 56px; height: 56px; object-fit: contain; }
.nested[hidden] { display: none; }
.option { border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.option label, .option .option-row { display: flex; align-items: center; gap: var(--ui-space-3); min-height: 52px; padding: var(--ui-space-1) var(--w-gap-tight); cursor: pointer; }
/* The chosen treatment on a LIST ROW rather than a card: same fill, same red line, but the line
   is the row's leading edge instead of a box, because these rows sit in an edge-to-edge stack
   inside a 560px sheet and a full outline around one of them reads as an error box. The mark is
   the native radio or checkbox, in Brand Red. */
.option:has(input:checked) > label, .option:has(> .option-row input:checked) > .option-row {
    background: var(--w-chosen-fill); box-shadow: inset var(--w-chosen-width) 0 0 var(--w-chosen-line);
}

.option .option-name { flex: 1; }
.option .option-price { font-size: 14px; color: var(--ui-text-secondary); white-space: nowrap; }
.option.is-sold-out { color: var(--ui-text-secondary); }
.option.is-sold-out label { cursor: not-allowed; }
.option .nested { padding-left: var(--ui-space-8); padding-bottom: var(--ui-space-2); }

.stepper { display: inline-flex; align-items: center; border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-40); }
.stepper button {
    width: var(--w-tap-inline); height: var(--w-tap-inline); border: 0; background: none; cursor: pointer; padding: 0; color: var(--ui-black);
    display: inline-flex; align-items: center; justify-content: center; border-radius: var(--ui-radius-40);
}
.stepper button[disabled] { color: var(--ui-grey-300); cursor: not-allowed; }
.stepper output, .stepper .qty { min-width: 28px; text-align: center; font-weight: 400; }

.sheet-foot { border-top: var(--ui-border-100) solid var(--ui-grey-200); padding: var(--ui-space-3) var(--ui-space-4) calc(var(--ui-space-3) + env(safe-area-inset-bottom)); background: var(--ui-white); }
.sheet-foot .row { display: flex; gap: var(--ui-space-3); align-items: center; }
.sheet-foot .btn { flex: 1; padding: 0 var(--ui-space-3); white-space: nowrap; }
/* In the sheet the add bar is the foot itself: not sticky, no outer margin. */
.sheet-foot .add-bar { position: static; margin: 0; }
.add-bar .stepper { border: 0; color: var(--ui-white); }
.add-bar .stepper button { color: var(--ui-white); }
.add-bar .stepper button[disabled] { color: var(--ui-grey-600); }
.add-bar .stepper output { font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; font-size: 18px; }
.sheet-error { margin: 0 0 var(--ui-space-2); }

/* ------------------------------------------------------------------ forms (inputs radius 4) */
.field { margin: 0 0 var(--ui-space-4); }
.field label, .label { display: block; font-weight: 400; font-size: 14px; line-height: 20px; margin-bottom: var(--ui-space-2); }
.field .hint { font-size: 12px; line-height: 16px; color: var(--ui-text-secondary); margin: var(--ui-space-1) 0 0; }
.input, .field input, .field select, .field textarea {
    width: 100%; min-height: var(--tap); padding: var(--ui-space-3);
    border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-40);
    background: var(--ui-white); font-size: 16px; font-weight: 400;
}
.field textarea { min-height: 88px; resize: vertical; }
/* ------------------------------------------------------------------ delivery pin (address-map.js)
   Leaflet on OpenStreetMap. A structural frame (1px control line, Radius 100 like a selectable
   card), a fixed height (240px on a phone, taller where there is room), the pin as KFC's functional
   map-pin icon in black on a white disc. Leaflet's own chrome (zoom buttons, attribution) keeps
   its vendor CSS; only its type and corners are brought onto KFC's tokens. */
/* The rider leg on the order page's black stage: white type, the rider and time in the Sans. */
.order-delivery { margin: var(--ui-space-4) 0 0; }
.order-delivery[hidden], .order-delivery [hidden] { display: none; }
.order-delivery p { margin: 0 0 var(--ui-space-1); font-size: 16px; line-height: 24px; }
.order-delivery strong { font-weight: 400; }
.address-map-canvas {
    height: 240px; margin-top: var(--ui-space-2);
    border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-100);
    overflow: hidden; background: var(--ui-grey-50);
}
@media (min-width: 768px) { .address-map-canvas { height: 320px; } }
html:not(.js) .address-map-canvas { display: none; }
.address-map-canvas.leaflet-container { font-family: var(--ui-font-body); }
.address-map-canvas .leaflet-bar a { color: var(--ui-black); }
.address-map-canvas .leaflet-bar, .address-map-canvas .leaflet-bar a:first-child, .address-map-canvas .leaflet-bar a:last-child { border-radius: var(--ui-radius-40); }
.address-map-canvas .leaflet-control-attribution { font-size: 12px; line-height: 16px; }
.address-map-canvas .leaflet-control-attribution a { color: var(--ui-black); }
.address-map-pin {
    display: flex; align-items: center; justify-content: center; width: 40px; height: 40px;
    border-radius: var(--ui-radius-100); background: var(--ui-white); color: var(--ui-black);
    box-shadow: 0 0 0 var(--ui-border-100) var(--ui-black);
}
.leaflet-marker-icon.address-map-marker { background: none; border: 0; }
.address-map-actions { display: flex; gap: var(--w-gap-inline); margin-top: var(--ui-space-2); }
.address-map-actions [hidden] { display: none; }
.address-map-status { margin: var(--ui-space-2) 0 0; font-size: 14px; line-height: 20px; }
.address-map-status[hidden] { display: none; }
.address-map-status.is-error { color: var(--ui-error-dark); }
.address-map-status strong { font-weight: 400; }
.address-map.is-missing .address-map-canvas { border-color: var(--ui-error-main); }
.summary .row[hidden] { display: none; }

/* A checkbox or radio inside a .field is the one control above, never a full-width input. */
.field input[type="checkbox"], .field input[type="radio"] { width: 22px; min-height: 0; height: 22px; padding: 0; }
.input:hover, .field input:hover, .field select:hover, .field textarea:hover { border-color: var(--ui-black); }
.input:focus, .field input:focus, .field select:focus, .field textarea:focus { border-color: var(--ui-black); outline: var(--ui-focus-width) solid var(--ui-focus); outline-offset: 2px; }
/* The floating label, notched into the field's top border (KFC ui-border, input examples): one
   rule for every labelled input, select and textarea on the storefront. The label keeps its own
   element and its `for` — this is placement only — and sits on the field's own white. It turns
   black on focus and Error Main when the field is invalid (stated). Not in the back office. */
body:not(.admin) .field:has(> label + :is(input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]), select, textarea)) { position: relative; padding-top: var(--ui-space-2); }
body:not(.admin) .field:has(> label + :is(input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]), select, textarea)) > label {
    position: absolute; top: 0; left: var(--ui-space-2); z-index: 1; max-width: calc(100% - var(--ui-space-4)); margin: 0; padding: 0 var(--ui-space-1);
    background: var(--ui-white); font-size: 12px; line-height: 16px; color: var(--ui-grey-500); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
body:not(.admin) .field:has(> label + :is(input, select, textarea):focus) > label { color: var(--ui-black); }
body:not(.admin) .field:has(> label + [aria-invalid="true"]) > label { color: var(--ui-error-main); }
/* Invalid is a red BOUNDARY, not red typing: the customer's own name came back at them in error
   red, which reads as though the characters were wrong rather than the field being empty. */
.field input[aria-invalid="true"] { border-color: var(--ui-error-main); }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--ui-space-3); }
fieldset.form-step { border: 0; padding: 0; margin: 0 0 var(--ui-space-6); min-width: 0; }
fieldset.form-step legend { padding: 0; margin-bottom: var(--ui-space-4); }
.section-rule { border: 0; border-top: var(--ui-border-100) solid var(--ui-grey-200); margin: var(--ui-space-6) 0; }

/* Narrow pages: the max-width is the CONTENT width, so add the grid margins back. */
.narrow { max-width: 560px; }
.wrap.narrow { max-width: calc(560px + 2 * var(--ui-grid-margin)); }
.wrap.narrow.track { max-width: calc(640px + 2 * var(--ui-grid-margin)); }  /* order status: long status on one line */

/* ------------------------------------------------------------------ cart / order summaries */
.two-col { display: grid; gap: var(--ui-space-8); }
@media (min-width: 1136px) { .two-col { grid-template-columns: minmax(0, 1fr) 380px; align-items: start; gap: var(--ui-space-12); } }

.lines { list-style: none; margin: 0; padding: 0; border-top: var(--ui-border-400) solid var(--ui-black); }
/* "Add to your order" (Deliverect Upsells API), right after an add: up to three option cards in
   the menu's own language - white, control line, the photo, the name, the price, one outlined tap. */
.cart-addons { margin: var(--ui-space-6) 0; }
.cart-addons-title { margin: 0 0 var(--ui-space-3); font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 24px; line-height: 24px; color: var(--ui-primary); }
.cart-addons-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--ui-space-3); }
.cart-addon { display: flex; flex-direction: column; align-items: center; gap: var(--ui-space-2); padding: var(--ui-space-3); border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-100); text-align: center; }
.cart-addon-photo { width: 96px; height: 96px; object-fit: contain; }
.cart-addon-name { font-size: 16px; line-height: 20px; }
.cart-addon-price { font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); }
.cart-addon form, .cart-addon .cart-addon-add { width: 100%; }
/* M5: a 1:1 menu photo is the first column (spec §6 puts menu photography in the cart and the
   checkout order summary). The photo spans every text row, so the line reads as one block. */
/* P1-6. The row was ~150px tall on a phone: three text rows, then a full-width actions row that
   started back under the photograph, so the quantity control belonged to the line visually only
   by being underneath it. The actions now sit in the text column, the padding is one step
   tighter and the unit line only renders when the quantity is more than one (which is the rule
   the kiosk cart already follows). Nothing was removed. */
.line { display: grid; grid-template-columns: var(--w-thumb) minmax(0, 1fr) auto; gap: var(--ui-space-1) var(--ui-space-3); padding: var(--ui-space-3) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.line-photo { grid-column: 1; grid-row: 1 / span 4; width: var(--w-thumb); height: var(--w-thumb); object-fit: contain; align-self: start; }
/* The same product, in the same face and the same casing, as the card it was added from and as
   the kiosk's own cart line (--w-type-item). */
.line-name { grid-column: 2; font-family: var(--ui-font-body); font-style: normal; font-weight: 400; text-transform: none; font-size: var(--w-type-item); line-height: 22px; }
.line-summary { grid-column: 2 / -1; font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); margin: 0; }
/* p2: at quantity 12 the line read "AWG 1.114,00" with no unit price anywhere on the page. */
.line-unit { grid-column: 2 / -1; font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); margin: 0; }
.line-unit[hidden] { display: none; }
.line-total { grid-column: 3; font-weight: 400; white-space: nowrap; }
.line-actions { grid-column: 2 / -1; display: flex; align-items: center; gap: var(--ui-space-4); margin-top: var(--ui-space-1); }
/* An unavailable line has no photo: its text takes the whole row back. */
.line.is-unavailable .line-name, .line.is-unavailable .line-summary { grid-column: 1 / -1; }
.line.is-unavailable .line-name { color: var(--ui-text-secondary); }

.summary { border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100); padding: var(--ui-space-5); }
.summary h2 { margin-bottom: var(--ui-space-4); }
.summary dl { margin: 0 0 var(--ui-space-4); }
.summary .row { display: flex; justify-content: space-between; gap: var(--ui-space-3); padding: var(--ui-space-1) 0; }
.summary dt, .summary dd { margin: 0; }
.summary .total { border-top: var(--ui-border-300) solid var(--ui-black); margin-top: var(--ui-space-2); padding-top: var(--ui-space-3); font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: 22px; line-height: 24px; }
.summary .tax-note { font-size: 14px; color: var(--ui-text-secondary); }
.summary-lines { list-style: none; padding: 0; margin: 0 0 var(--ui-space-3); font-size: 14px; line-height: 20px; }
.summary-lines li { display: flex; align-items: center; justify-content: space-between; gap: var(--ui-space-3); padding: var(--ui-space-2) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.summary-lines li > span { flex: 1; min-width: 0; }
.summary-lines .line-photo { flex: none; width: 56px; height: 56px; object-fit: contain; }
.summary-lines strong { white-space: nowrap; }
.summary-lines .sub { display: block; font-size: 12px; line-height: 16px; color: var(--ui-text-secondary); }

/* M7: the checkout order summary is the SECOND column of .two-col, so below 1136px it stacked
   after the whole form and after the CTA — a customer could place an order without ever having
   seen what they were buying. Below the breakpoint it goes first and collapses to a count and a
   total; at 1136px it is a column again and checkout.js reopens it. */
/* P0-2. One compact row: "Your order" over "4 items" on the left, the figure and the chevron on
   the right, each of them on ONE line. The old row put the heading and a single
   "4 items · AWG 69,80" string in competition for the same 318px and both of them wrapped —
   which made the one control on the page that tells a customer what they are about to pay for
   look like a rendering accident. */
details.summary > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--w-gap-inline); }
details.summary > summary::-webkit-details-marker { display: none; }
.summary-label { display: flex; flex-direction: column; gap: var(--ui-space-1); min-width: 0; }
details.summary > summary h2 { margin: 0; font-size: 20px; line-height: 24px; }
.summary-count { font-size: 14px; line-height: 20px; font-weight: 400; color: var(--ui-text-secondary); }
.summary-amount { margin-left: auto; font-size: 18px; line-height: 24px; font-weight: 400; white-space: nowrap; }
.summary-toggle { flex: none; display: inline-flex; align-items: center; color: var(--ui-black); }
.motion-ok .summary-toggle { transition: transform var(--ui-dur-press) var(--ui-ease-out); }
details.summary[open] .summary-toggle { transform: rotate(180deg); }
details.summary[open] > summary { margin-bottom: var(--ui-space-4); }
/* Open, the count and the figure are the list and the Total row directly underneath, so the row
   keeps only what is still doing work: the heading and the way to shut it again. */
details.summary[open] .summary-count, details.summary[open] .summary-amount { display: none; }
@media (max-width: 1135px) { #order-summary { order: -1; } }
@media (min-width: 1136px) {
    details.summary > summary { cursor: default; }
    details.summary > summary h2 { font-size: 32px; line-height: 32px; }
    /* Above the breakpoint the summary is a column that is always open and never toggled. */
    .summary-count, .summary-amount, .summary-toggle { display: none; }
}

/* M6: the cart's own sticky checkout bar. Same component as the menu's cart bar; hidden at the
   width where the summary column is already beside the lines. */
.cart-bar-checkout { margin: var(--ui-space-6) calc(-1 * var(--ui-grid-margin)) 0; }
.cart-bar-checkout .btn { min-height: 44px; }
@media (min-width: 1136px) { .cart-bar-checkout { display: none; } }

.empty { padding: var(--ui-space-6) 0; }
.empty p { font-size: 18px; }

/* ------------------------------------------------------------------ card fields (Microform iframes) */
.card-box { height: var(--tap); border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-40); padding: var(--ui-space-1) var(--ui-space-3); background: var(--ui-white); }
.card-box.cvv { max-width: 140px; }

/* Payment in progress: KFC brand loader + status text (checkout.js toggles [hidden]). */
.processing { margin: var(--ui-space-4) 0 0; padding: var(--ui-space-3) 0; text-align: center; }
.processing[hidden] { display: none; }
.processing p { margin: var(--ui-space-2) 0 0; font-weight: 400; }
/* Brand loader on its own row, centred. 220px wide = the mark renders ~84px (it fills ~38% of the 4:5 frame). */
.status-motion, .kfc-motion.status-motion { display: block; width: 220px; max-width: 60%; margin: 0 auto; }
.status-motion[hidden], .kfc-motion.status-motion[hidden] { display: none; }
.status-motion .kfc-motion { display: block; width: 100%; }

/* 3DS challenge overlay (checkout.js toggles `hidden`) */
.challenge[hidden] { display: none; }
.challenge { display: flex; position: fixed; inset: 0; z-index: 60; background: var(--ui-scrim); align-items: center; justify-content: center; padding: var(--ui-space-3); }
.challenge-box { background: var(--ui-white); padding: var(--ui-space-4); max-width: 100%; border-radius: var(--ui-radius-200); }
.challenge-box iframe { width: 400px; max-width: 100%; height: 600px; max-height: 75vh; border: 0; display: block; margin: var(--ui-space-3) 0; }

/* ------------------------------------------------------------------ order tracking */
.track-title { color: var(--ui-primary); }
.status-block { margin: var(--ui-space-5) 0 var(--ui-space-4); text-align: center; }
.status-big { margin: 0 0 var(--ui-space-2); }
.progress { list-style: none; margin: 0 0 var(--ui-space-2); padding: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--ui-space-1); }
/* An order that never reached the kitchen has no progress to show, and `display: grid` above
   would otherwise beat the browser's own [hidden] rule and draw four empty bars. */
.progress[hidden] { display: none; }
/* The step the order is stuck ON when the restaurant has not confirmed it: amber, not red (the
   order is fine, it is late), and not filled, because that step has not actually happened. */
.progress li.is-stalled::before { background: var(--ui-warning-main); }
.progress li.is-stalled { color: var(--ui-grey-800); font-weight: 400; }
.progress li { font-size: 12px; line-height: 16px; color: var(--ui-text-secondary); }
.progress li::before { content: ""; display: block; height: 8px; background: var(--ui-grey-200); margin-bottom: var(--ui-space-2); transition: background-color var(--ui-dur-title-line) var(--ui-ease-out); }
.progress li.is-done { color: var(--ui-black); font-weight: 400; }
.progress li.is-done::before { background: var(--ui-primary); }
.order-meta { margin: var(--ui-space-5) 0; font-size: 14px; line-height: 20px; }
.payment-note { display: flex; align-items: center; gap: var(--ui-space-3); }

.orders-list { list-style: none; margin: 0; padding: 0; border-top: var(--ui-border-400) solid var(--ui-black); }
.orders-list a { display: grid; grid-template-columns: 1fr auto; gap: var(--ui-space-1) var(--ui-space-3); padding: var(--ui-space-4) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); text-decoration: none; min-height: var(--tap); }
.orders-list a:hover .order-number { color: var(--ui-primary); }
/* A row title in a list, like a cart line: the text face (--w-type-item), not the display one. */
.order-number { font-family: var(--ui-font-body); font-style: normal; font-weight: 400; font-size: var(--w-type-item); line-height: 22px; }
.orders-list .when { grid-column: 1; font-size: 14px; color: var(--ui-text-secondary); }
.orders-list .amount { font-weight: 400; text-align: right; }
.orders-list .state { grid-column: 2; font-size: 14px; text-align: right; }

.address-list { list-style: none; margin: 0 0 var(--ui-space-4); padding: 0; }
.address-list li { display: flex; align-items: center; justify-content: space-between; gap: var(--ui-space-3); padding: var(--ui-space-2) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.address-list li { flex-wrap: wrap; }
/* Edit (pin included) opens under the address, full width. */
.address-edit { flex-basis: 100%; }
.address-edit > summary { list-style: none; display: inline-block; }
.address-edit > summary::-webkit-details-marker { display: none; }
.address-edit[open] > summary { margin-bottom: var(--ui-space-3); }

.pagination-wrap { margin-top: var(--ui-space-5); }
.field input.code-input { font-size: 28px; letter-spacing: 0.3em; font-weight: 400; max-width: 240px; }
/* (the border width for an invalid field is set once, with the field errors below.) */

/* ------------------------------------------------------------------ brand motion (<x-kfc-motion>)
   The still (poster <img>) sits BEHIND the clip and is hidden only while the clip is actually
   playing. The clips have alpha, so a still under a playing frame would ghost through it — but a
   clip that never decodes, or whose autoplay is refused, has to leave the KFC mark on screen
   rather than a hole in the middle of a payment screen. motion.js adds .is-playing on `playing`
   and takes it off again on `error` or a refused play(). */
.kfc-motion { display: inline-block; position: relative; }
.kfc-motion video, .kfc-motion img { width: 100%; height: auto; display: block; }
.kfc-motion-still { position: absolute; inset: 0 0 auto 0; width: 100%; height: auto; }
.kfc-motion.is-playing .kfc-motion-still { visibility: hidden; }
.kfc-motion.is-done { visibility: hidden; }

/* ------------------------------------------------------------------ UI motion (MEASURED timings, stated easing)
   Everything below only runs with html.motion-ok (set by motion.js when reduced motion is off), so
   content never stays hidden if JS fails. */
@keyframes kfc-line-in { from { opacity: 0; transform: translateY(var(--ui-line-offset, .5em)); } to { opacity: 1; transform: none; } }
/* Review #38: hidden only once motion.js is actually running reveals (html.reveal-on), never on
   the strength of the <head> flag alone: a script that fails to load, or a crawler, a print or a
   full-page capture, sees every section instead of blank bands. */
.motion-ok.reveal-on [data-reveal]:not(.is-in) { opacity: 0; }
/* Anything already on screen at first paint is never revealed: motion.js marks it instant, so a
   scroll-reveal can never be the reason the largest element on the page paints late. */
.motion-ok [data-reveal].is-instant { animation: none !important; opacity: 1; }
.motion-ok [data-reveal="title"].is-in { --ui-line-offset: .4em; animation: kfc-line-in var(--ui-dur-title-line) var(--ui-ease-out) both; animation-delay: calc(var(--i, 0) * var(--ui-stagger-title)); }
.motion-ok [data-reveal="body"].is-in { --ui-line-offset: .5em; animation: kfc-line-in 300ms var(--ui-ease-out) both; animation-delay: calc(var(--i, 0) * var(--ui-stagger-body)); }
/* Line by line (ui-motion 02 / 03): motion.js splits the words and numbers them by LINE; the
   element itself is then simply shown, and each line rises in on its own delay. */
.kfc-lw { display: inline-block; }
.motion-ok [data-reveal][data-lines="1"].is-in { animation: none; opacity: 1; }
.motion-ok [data-reveal="title"][data-lines="1"].is-in .kfc-lw { --ui-line-offset: .4em; animation: kfc-line-in var(--ui-dur-title-line) var(--ui-ease-out) both;
    animation-delay: calc(var(--i, 0) * 230ms); }
.motion-ok [data-reveal="body"][data-lines="1"].is-in .kfc-lw { --ui-line-offset: .5em; animation: kfc-line-in 150ms var(--ui-ease-out) both;
    animation-delay: calc(var(--i, 0) * 130ms); }
.motion-ok [data-reveal].is-instant .kfc-lw { animation: none !important; }

/* Subtle emphasis (ui-motion 04, MEASURED): the photo settles from 1.045 to 1 over ~6s, in its frame. */
@keyframes kfc-kenburns { from { transform: scale(1.045); } to { transform: scale(1); } }
.motion-ok .kfc-emphasis.kfc-emphasis-in { animation: kfc-kenburns 6000ms var(--ui-ease-out) both; }
.product-page-photo { overflow: hidden; }

/* Scroll-linked (ui-motion 09-12), where the browser has scroll timelines; elsewhere, still.
   Image: a lifestyle banner opens from a strip to its full height as it reaches the centre.
   Header: the home hero photo moves at half the speed of the page, under the panel. */
@supports (animation-timeline: view()) {
    @keyframes kfc-grow { from { clip-path: inset(30% 0 30% 0); } to { clip-path: inset(0 0 0 0); } }
    .motion-ok .home-world img, .motion-ok .home-parties img, .motion-ok .page-banner img {
        animation: kfc-grow linear both; animation-timeline: view(); animation-range: entry 0% cover 45%; }
    @keyframes kfc-header-par { from { transform: translateY(0); } to { transform: translateY(50%); } }
    .motion-ok .home-hero .home-slide:first-child .home-slide-img, .motion-ok .home-hero > .home-slide .home-slide-img {
        animation: kfc-header-par linear both; animation-timeline: scroll(root); animation-range: 0 100vh; }
}
.home-slide { overflow: hidden; }

/* Sheet open/close 280ms: slide up on phones, rise + fade on desktop. Close = .is-closing. */
@keyframes kfc-sheet-up { from { transform: translateY(100%); } to { transform: none; } }
@keyframes kfc-sheet-down { from { transform: none; } to { transform: translateY(100%); } }
@keyframes kfc-modal-in { from { opacity: 0; transform: translate(-50%, calc(-50% + 40px)); } to { opacity: 1; transform: translate(-50%, -50%); } }
@keyframes kfc-modal-out { from { opacity: 1; transform: translate(-50%, -50%); } to { opacity: 0; transform: translate(-50%, calc(-50% + 40px)); } }
@keyframes kfc-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes kfc-fade-out { from { opacity: 1; } to { opacity: 0; } }
.motion-ok dialog.sheet[open] { animation: kfc-sheet-up var(--ui-dur-sheet) var(--ui-ease-out); }
.motion-ok dialog.sheet[open].is-closing { animation: kfc-sheet-down var(--ui-dur-sheet) var(--ui-ease-standard) forwards; }
.motion-ok dialog.sheet[open]::backdrop { animation: kfc-fade-in var(--ui-dur-sheet) var(--ui-ease-out); }
.motion-ok dialog.sheet[open].is-closing::backdrop { animation: kfc-fade-out var(--ui-dur-sheet) var(--ui-ease-standard) forwards; }
@media (min-width: 600px) {
    .motion-ok dialog.sheet[open] { animation-name: kfc-modal-in; }
    .motion-ok dialog.sheet[open].is-closing { animation-name: kfc-modal-out; }
}

/* Skeleton -> content: the sheet shows "Loading" until the product arrives. Fading the real
   content in tells the customer the wait ended; it is 180ms, so it never feels like more waiting. */
@keyframes kfc-content-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.motion-ok .sheet-body.is-ready > * { animation: kfc-content-in 180ms var(--ui-ease-out) both; }

/* Page transitions between storefront routes. Cross-document, so back/forward keep working, the
   URLs stay real and a browser without View Transitions simply navigates. Reduced motion turns
   the animations off above, which leaves an instant swap. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: kfc-fade-out 140ms var(--ui-ease-in) both; }
::view-transition-new(root) { animation: kfc-fade-in 220ms var(--ui-ease-out) both; }
/* PLP -> PDP push and back (ui-motion 08, MEASURED ~450-475ms each way, ease.standard). */
@keyframes kfc-out-left { to { transform: translateX(-100%); } }
@keyframes kfc-in-right { from { transform: translateX(100%); } }
@keyframes kfc-out-right { to { transform: translateX(100%); } }
@keyframes kfc-in-left { from { transform: translateX(-100%); } }
html:active-view-transition-type(push)::view-transition-old(root) { animation: kfc-out-left var(--ui-dur-page) var(--ui-ease-standard) both; }
html:active-view-transition-type(push)::view-transition-new(root) { animation: kfc-in-right var(--ui-dur-page) var(--ui-ease-standard) both; }
html:active-view-transition-type(pop)::view-transition-old(root) { animation: kfc-out-right var(--ui-dur-page) var(--ui-ease-standard) both; }
html:active-view-transition-type(pop)::view-transition-new(root) { animation: kfc-in-left var(--ui-dur-page) var(--ui-ease-standard) both; }

/* Add-to-cart success: subtle emphasis scale on the product button, count bump in the header. */
@keyframes kfc-emphasis { 0% { transform: scale(1); } 40% { transform: scale(1.045); } 100% { transform: scale(1); } }
@keyframes kfc-bump { 0% { transform: translateY(0); } 35% { transform: translateY(-40%); opacity: 0; } 36% { transform: translateY(40%); } 100% { transform: none; opacity: 1; } }
.motion-ok .is-emphasis { animation: kfc-emphasis 450ms var(--ui-ease-out); }
.motion-ok .is-bump { display: inline-block; animation: kfc-bump 300ms var(--ui-ease-standard); }

/* Reduced motion means NOT animating, not animating faster: `animation: none` rather than a 1ms
   duration. Nothing here depends on an animationend firing — menu.js closes the sheet instantly
   when reduced motion is on, and motion.js's replay() returns early — and no [data-reveal] can be
   left invisible, because html.motion-ok is absent, which is what hides them in the first place. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation: none !important;
        transition: none !important;
        scroll-behavior: auto !important;
    }
    ::view-transition-old(root), ::view-transition-new(root) { animation: none !important; }
    .btn:active { transform: none; }
    .btn-roll > span + span { display: none; }
    .btn-roll > span:first-child { transform: none !important; }
    video[data-kfc-motion] { display: none; }
    /* Nothing plays, so the still is the whole clip and takes the wrapper's height back. */
    .kfc-motion-still { position: static; visibility: visible; }
}

/* "Nearest to you: X · Switch" (store-locate.js, when the customer is already using the page). */
.nearest-line .nearest-switch { display: inline-flex; align-items: center; min-height: 24px; padding: 0 var(--ui-space-1); font-size: 14px; }

/* ------------------------------------------------------------------ error pages (resources/views/errors/)
   Product surface, not a stack trace: KFC header and footer, one heading, one line, one way out. */
/* P2-9. The copy is right; it was floating. The block is centred on its own axis rather than
   left-ranged inside a centred column, and the 64px of padding under it — on top of the page's
   own 56 — left roughly 140px of nothing between "Find a KFC restaurant" and the footer rule.
   The page frame owns the bottom space now, so there is one gap and not two. */
.error-page { padding: var(--w-gap-block) 0 0; max-width: 560px; margin: 0 auto; text-align: center; }
.error-page h1 { color: var(--ui-black); }  /* the red is the Stripes wall above it (brand/rewards) */
.error-lead { margin: var(--w-gap-block) 0 var(--w-gap-section); font-size: 18px; line-height: 24px; }
.error-second { margin: var(--w-gap-block) 0 0; }

/* ------------------------------------------------------------------ breadcrumbs
   Plain text trail, Sans Regular caps at caption size. No chevron icons: the separator is
   typographic so it never reads as a functional icon (spec §5). */
.breadcrumbs { margin: 0 0 var(--ui-space-3); }
@media (min-width: 600px) { .breadcrumbs { margin-bottom: var(--ui-space-5); } }
.breadcrumbs ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--ui-space-1) 0; font-size: 12px; line-height: 16px; }
.breadcrumbs li + li::before { content: "/"; margin: 0 var(--ui-space-2); color: var(--ui-grey-300); }
.breadcrumbs a { color: var(--ui-text-secondary); text-decoration: none; text-underline-offset: 3px; }
.breadcrumbs a:hover { color: var(--ui-black); text-decoration: underline; }
.breadcrumbs [aria-current="page"] { color: var(--ui-black); }

/* ------------------------------------------------------------------ product page (/menu/{category}/{product})
   The indexable surface for one item, and the ordering path with JavaScript switched off: the
   modifier groups below are a real <form> that posts to /cart/lines. */
/* P0. On a 390x844 phone the photograph was 292px of a 4:3 box, the heading took two lines of
   32px, the description two more and the restaurant status a further two rows with a 48px tap
   target under it — so the first thing the page actually ASKS ("Original Recipe or Hot &
   Spicy?") began at y=723 and its options were off the bottom of the glass. The photograph is a
   header here, not a poster: the kiosk cut its sheet's image from 320 to 200 for the same
   reason and this is that decision at phone scale. Nothing is removed, only sized. */
/* KFC's PDP (pdp-desktop). Phone: back, photo, the Stripes name, then the details, the photo a
   header rather than a poster (the options are the question the page exists to ask). 1136+: the
   photo column takes seven of twelve columns with the Stripes name running under it, clipped at
   the column's edge; the details take the other five. */
.product-page { display: grid; gap: var(--w-gap-inline); position: relative; }
.back-button { display: inline-flex; align-items: center; justify-content: center; width: var(--w-tap-inline); height: var(--w-tap-inline);
    border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-40); background: var(--ui-white); color: var(--ui-black); }
.back-button:hover { border-color: var(--ui-black); }
.product-page-photo-col { min-width: 0; overflow: hidden; margin: 0 calc(-1 * var(--ui-grid-margin)); padding: 0 var(--ui-grid-margin); }
.product-page-photo { aspect-ratio: var(--w-card-media); max-height: 220px; display: flex; align-items: center; justify-content: center; }
@media (min-width: 600px) { .product-page { gap: var(--w-gap-block); } .product-page-photo { max-height: 320px; } }
.product-page-photo img { width: 100%; height: 100%; object-fit: contain; }
/* A cut-out is 480x360: shown at most at its own size, never scaled up soft. */
.product-page-photo img.is-cutout { max-width: 480px; max-height: 360px; }
/* The Stripes name: Hero-XL, running off the right edge of the SCREEN (main clips it), never cut
   at a column (QA E19). Phone: straight under the photo (grid order). 1136+: a full-bleed band
   under both columns, the first word on the content edge. */
.product-page > .back-button { order: 0; }
.product-page > .product-page-photo-col { order: 1; }
.pdp-stripes { order: 2; font-size: var(--t-hero-xl); margin-top: var(--ui-space-2); }
.product-page > .product-page-detail { order: 3; }
@media (min-width: 1136px) {
    .pdp-stripes { order: 4; grid-column: 1 / -1; margin-top: var(--w-gap-section);
        margin-left: calc(50% - 50vw); padding-left: calc(50vw - 50%); margin-right: calc(50% - 50vw); }
}
@media (min-width: 1136px) {
    .product-page { grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--ui-grid-gutter); align-items: start; }
    .back-button { grid-column: 1 / -1; }
    .product-page-photo-col { grid-column: 1 / span 7; margin-right: 0; padding-right: 0; }
    .product-page-photo { max-height: 480px; }
    .product-page-detail { grid-column: 9 / -1; }
}
.product-page-detail h1 { overflow-wrap: anywhere; font-size: var(--t-h2); }
.product-page-price { font-weight: 400; font-size: 16px; line-height: 24px; margin: var(--ui-space-3) 0 var(--ui-space-3); }
.product-page-desc { margin-bottom: var(--ui-space-4); }
/* Serif Heavy Italic, underlined, black (pdp-desktop): a link, set as KFC sets it. */
.pdp-allergy { margin: 0 0 var(--w-gap-block); }
.pdp-allergy a { font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; font-size: 18px; line-height: 24px; color: var(--ui-black); text-underline-offset: 3px; }
.pdp-allergy a:hover { color: var(--ui-primary-text); }
/* One compact notice line: where this price is from, whether that restaurant is taking orders,
   and the way to change it — all on one baseline. */
.product-page-where {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--ui-space-1) var(--w-gap-tight);
    margin: 0; padding-bottom: var(--w-gap-tight);
}
.product-page-where .text-link { min-height: 0; margin-left: auto; }
/* The choices start under KFC's 4px primary divider ("RECIPE" in the example). */
.product-page-form { border-top: var(--ui-border-400) solid var(--ui-black); }
.product-page-form .option-qty { width: 72px; min-height: var(--tap); padding: 0 var(--ui-space-2); text-align: center;
    border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-40); background: var(--ui-white); }

/* The add bar (pdp-desktop, and the sheet's foot): a black bar with radius 4, a white − 1 +
   stepper and the red button carrying the price on the left and ADD on the right. Sticky at the
   foot of the screen on the product page, above the phone tab bar. */
.add-bar { position: sticky; bottom: var(--ui-space-2); z-index: 5; display: flex; align-items: center; gap: var(--ui-space-3);
    margin-top: var(--w-gap-block); padding: var(--ui-space-2); background: var(--ui-black); color: var(--ui-white);
    border-radius: var(--ui-radius-40); border-top: var(--ui-border-400) solid var(--ui-black); }
@media (max-width: 599px) { .add-bar { bottom: calc(var(--tab-h) + env(safe-area-inset-bottom) + var(--ui-space-2)); } }
.add-bar-qty { display: flex; align-items: center; }
.add-bar-qty input { width: 48px; min-height: var(--w-tap-inline); border: 0; background: transparent; color: var(--ui-white); text-align: center;
    font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; font-size: 18px; -moz-appearance: textfield; }
.add-bar-qty input::-webkit-outer-spin-button, .add-bar-qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.add-bar-step { width: var(--w-tap-inline); height: var(--w-tap-inline); display: inline-flex; align-items: center; justify-content: center;
    border: 0; border-radius: var(--ui-radius-40); background: transparent; color: var(--ui-white); cursor: pointer; }
.add-bar-step[hidden] { display: none; }
.add-bar :focus-visible { outline-color: var(--ui-white); }
.add-bar-go { flex: 1; justify-content: space-between; min-height: var(--w-tap-inline); white-space: nowrap; padding: 0 var(--ui-space-4); }
/* Review #39: the price is white on Brand Red too, so it is large text (19px Heavy) at every width. */
.add-bar-go .add-price { font-size: var(--ui-cta-size); }
/* ...and so on a narrow phone with a long total ("AWG 642,00" x "AGREGA") the verb drops under the
   price instead of the button running off the screen: the same trade the pay bar makes. */
@media (max-width: 599px) {
    .add-bar-go { min-width: 0; flex-wrap: wrap; white-space: normal; column-gap: var(--ui-space-3); row-gap: 0; padding-top: var(--ui-space-1); padding-bottom: var(--ui-space-1); }
    .add-bar-go .add-price { white-space: nowrap; }
    .add-bar-go > span:last-child { margin-left: auto; }
}

/* An optional campaign colour behind the whole PDP (secondary palette, stated): Herbs, Spices or
   black. Text stays black on Herbs/Spices (AA), white on black. Set per product in
   config('site.product_accents'); none by default. The studio-white packshot DARKENS onto it: white
   becomes the colour, and the food (already darker than Herbs/Spices in most channels) keeps its own. */
main:has(.pdp-accent-herbs) { background: var(--ui-accent-1); }
main:has(.pdp-accent-spices) { background: var(--ui-accent-2); }
main:has(.pdp-accent-black) { background: var(--ui-black); color: var(--ui-white); }
.pdp-accent .product-page-photo img { mix-blend-mode: darken; }   /* studio white takes the colour; the food keeps its own */
.pdp-accent-black .pdp-allergy a { color: var(--ui-white); }
.category-back { margin-top: var(--ui-space-10); }

/* ------------------------------------------------------------------ checkout field errors (B3)
   The message lives inside the .field it names, under the input, with the input marked
   aria-invalid and outlined in Error Main. #place-errors keeps only errors that name no field. */
.field-error { margin: var(--ui-space-1) 0 0; font-size: 14px; line-height: 20px; }
.field input[aria-invalid="true"], .field select[aria-invalid="true"], .field textarea[aria-invalid="true"] {
    border-color: var(--ui-error-main); border-width: 2px;
}
/* P1-6: the heavy double outline. A focused invalid field drew a 2px red box, a 2px white gap
   and a 2.5px black ring around that — three concentric boundaries on an empty Name field. The
   ring stays (it is the site's one focus indicator and it is 21:1) but it sits ON the red edge
   instead of outside a gap, so the field reads as one two-tone boundary. */
.field input[aria-invalid="true"]:focus, .field select[aria-invalid="true"]:focus, .field textarea[aria-invalid="true"]:focus {
    outline-offset: 0;
}

/* A completed step, collapsed to one line with a way back into it (B4). */
.step-summary { display: flex; align-items: baseline; gap: var(--ui-space-3); margin: 0 0 var(--ui-space-6);
    padding: var(--ui-space-3) 0; border-top: var(--ui-border-100) solid var(--ui-grey-200);
    border-bottom: var(--ui-border-100) solid var(--ui-grey-200); font-size: 14px; line-height: 20px; }
.step-summary[hidden] { display: none; }
.step-summary p { margin: 0; flex: 1; min-width: 0; }
.step-summary .link-button { flex: none; min-height: 0; }
#payment-heading:focus-visible { outline-offset: 6px; }

/* Menu search: one input and one button, on the grid. Server-side (GET /menu?q=). */
.menu-search { display: flex; gap: var(--ui-space-2); margin-top: var(--ui-space-4); max-width: 520px; }
.menu-search input { flex: 1; min-width: 0; min-height: var(--tap); padding: var(--ui-space-3);
    border: var(--ui-border-100) solid var(--ui-control-line); border-radius: var(--ui-radius-40);
    background: var(--ui-white); font-size: 16px; font-weight: 400; }
.menu-search input:hover { border-color: var(--ui-black); }
.menu-search .btn { flex: none; }

/* ------------------------------------------------------------------ KFC ARUBA REWARDS
 * /rewards, /coupon/{token}, /staff*. Its own thin shell (kfc-aruba.com gives the programme one),
 * the same tokens as everything else. The QR is the one thing on these pages that is designed for
 * a machine: black on white, a white frame around it even in a dark room, never tinted, never
 * shrunk below a size a scanner at arm's length can read.
 */
.rewards-header .wrap { display: flex; align-items: center; justify-content: space-between; }
.rewards-mark { margin: 0; color: var(--ui-white); font-family: var(--ui-font-heading); font-style: italic; text-transform: uppercase; font-size: 18px; line-height: 24px; }
.rewards-footer { border-top: var(--ui-border-100) solid var(--ui-grey-200); margin-top: var(--w-gap-section); padding: var(--ui-space-6) 0 var(--ui-space-8); font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); }
.rewards-footer p { margin: 0 0 var(--ui-space-2); }
.rewards-footer a { color: var(--ui-text); text-underline-offset: 3px; }
.rewards-form .check label { display: flex; gap: var(--ui-space-3); align-items: flex-start; font-weight: 400; }
/* The site's 22px checkbox (cd4afc6). `width: auto` here used to collapse it to a 2px bar. */
.rewards-form .check input { margin-top: 1px; flex: none; min-height: 0; }   /* hairline: the 22px box on the first line */
.phone-row { display: grid; grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); gap: var(--ui-space-2); }
.rewards-note { margin-top: var(--ui-space-3); }

.coupon-qr { background: var(--ui-white); padding: var(--ui-space-3); width: min(100%, 320px); margin: var(--w-gap-inline) 0; border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100); }
.coupon-qr svg { display: block; width: 100%; height: auto; }
.member-qr { width: min(100%, 260px); }
.coupon-show { font-size: 20px; line-height: 1; margin: 0 0 var(--ui-space-1); }
.coupon-valid { margin: 0 0 var(--ui-space-3); }
/* The old site's human reference (KFC-XXXX-XXXX), read aloud at a drive-thru speaker. */
.coupon-reference { margin: 0 0 var(--ui-space-1); font-weight: 400; }
/* A code a person reads back (coupon, reference): KFC Sans Regular with tabular figures, not a
   system monospace - the brand has three faces and a code is still type a customer reads. */
.mono { font-family: var(--ui-font-body); font-weight: 400; font-variant-numeric: tabular-nums; letter-spacing: .04em; }

.staff-shift { font-size: 14px; line-height: 20px; color: var(--ui-text-secondary); margin: var(--ui-space-4) 0; }
.inline-form { display: inline; }
.inline-form .text-link { background: none; border: 0; padding: 0; cursor: pointer; font: inherit; min-height: 0; }
/* .scan-result: see brand/rewards at the end of the file. */
.member-coupons { list-style: none; margin: var(--ui-space-3) 0 0; padding: 0; }
.member-coupons li { padding: var(--ui-space-3) 0; border-top: var(--ui-border-100) solid var(--ui-grey-200); }
.member-coupons p { margin: 0 0 var(--ui-space-2); }
.scan-form { margin-bottom: var(--w-gap-block); }
.scan-form label { display: block; margin-bottom: var(--ui-space-2); }
.scan-form input { width: 100%; margin-bottom: var(--ui-space-3); font-size: 22px; min-height: 64px; }
.scan-form .btn { margin-bottom: var(--ui-space-3); }
.scan-form video { width: 100%; aspect-ratio: 1; object-fit: cover; background: var(--ui-black); border-radius: var(--ui-radius-100); margin-bottom: var(--ui-space-3); }
/* .btn sets display, which beats the UA's [hidden]: the camera button is hidden until the browser
   proves it has BarcodeDetector, and must stay hidden where it does not. */
.scan-form [hidden] { display: none; }
.account-rewards .coupon-qr { margin-top: var(--ui-space-3); }

/* The order entry page: one row per restaurant, the ways to order under its address. Side by side
   at 1440 the actions squeezed the address and hours into a column four words wide. */
.order-stores { list-style: none; margin: var(--w-gap-inline) 0 0; padding: 0; border-top: var(--ui-border-400) solid var(--ui-black); }
.order-stores > li { display: grid; gap: var(--ui-space-3); padding: var(--w-gap-block) 0; border-bottom: var(--ui-border-100) solid var(--ui-grey-200); }
.order-stores h2 { margin: 0 0 var(--ui-space-1); font-size: 22px; line-height: 1; }
.order-stores p { margin: 0; }
.order-store-actions { display: flex; flex-wrap: wrap; gap: var(--ui-space-2); align-items: center; }
.order-store-actions form { margin: 0; }

/* ------------------------------------------------------------------ offers (KFC mobile-offers-and-offer-detail)
   Tabs (Rewards / Offers), a red Serif overline over the H1, then the offers on a full-bleed black
   band. An offer card: the picture, the tags, the title in Serif caps, the price, the window.
   A packshot stands, cut out (tools/cutout.py), in a Bucket Device panel in Herbs (limited time:
   urgency) or Spices (everyday) and rises out of its rim. A lifestyle photo is cropped 3:4
   (carousel card, stated). Card radius 0. */
.offer-tabs { display: flex; gap: var(--w-gap-block); margin: 0 0 var(--w-gap-block); }
.offer-tabs a { display: inline-flex; align-items: center; min-height: var(--w-tap-inline); font-size: var(--t-subtitle-1); font-weight: 400; color: var(--ui-black);
    text-decoration: none; border-bottom: var(--ui-border-300) solid transparent; }
.offer-tabs a[aria-current="page"] { color: var(--ui-primary-text); border-bottom-color: var(--ui-primary-text); }
.overline-red { margin: 0 0 var(--ui-space-1); font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase;
    font-size: var(--t-h4); line-height: 1; color: var(--ui-primary); }
/* :not(.offer-card): a card on the band carries the variant class `offer-band` too, and inherited
   the band's negative margins and black fill, so each card's box ran 80px over its neighbour and
   hid the end of that card's title ("OG CHICKEN COMBO", QA). */
.offer-band:not(.offer-card) { margin: var(--w-gap-block) calc(-1 * var(--ui-grid-margin)) 0; padding: var(--w-gap-block) var(--ui-grid-margin) var(--w-gap-section);
    background: var(--ui-black); color: var(--ui-white); }
.offer-band .promo-group { margin-top: var(--w-gap-block); }
.offer-band .promo-group:first-child { margin-top: 0; }
.offer-band .promo-group > h2 { color: var(--ui-white); }
.offer-band .promo-group-line { color: var(--ui-grey-200); }
.offer-list { list-style: none; margin: var(--w-gap-inline) 0 0; padding: 0; display: grid; gap: var(--w-gap-section) var(--ui-grid-gutter); }
@media (min-width: 600px) { .offer-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1136px) { .offer-list { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 900px) {
    .offer-list.offer-list-one { grid-template-columns: 1fr; }
    .offer-list-one .offer-card { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: var(--ui-space-12); align-items: end; }
    .offer-list-one .offer-media { grid-row: 1 / span 5; aspect-ratio: 3 / 2; margin: 0; }
    .offer-list-one .offer-media-cutout { aspect-ratio: 4 / 3; }
    .offer-list-one .offer-title { font-size: var(--t-h1); -webkit-line-clamp: 4; }
    .offer-list-one .offer-price { font-size: var(--t-subtitle-1); }
}
.offer-card { display: flex; flex-direction: column; gap: var(--ui-space-2); color: inherit; text-decoration: none; border-radius: var(--ui-radius-none); }
.offer-media { position: relative; display: block; aspect-ratio: 3 / 4; overflow: hidden; margin-bottom: var(--ui-space-2); }
.offer-media .offer-img { width: 100%; height: 100%; object-fit: cover; }
.offer-media-cutout { aspect-ratio: 4 / 3; }
.offer-bucket { position: absolute; left: 12%; right: 12%; top: 18%; bottom: 0; display: block;
    -webkit-mask: url("/images/kfc/bucket-device.svg") center / 100% 100% no-repeat; mask: url("/images/kfc/bucket-device.svg") center / 100% 100% no-repeat; }
.offer-herbs .offer-bucket { background: var(--ui-accent-1); }
.offer-spices .offer-bucket { background: var(--ui-accent-2); }
/* The cut-out stands in the bucket and rises out of its rim, as in KFC's example. */
.offer-media-cutout .offer-img { position: absolute; left: 8%; right: 8%; top: 0; bottom: 4%; width: 84%; height: 96%; object-fit: contain; }
.offer-tags { display: flex; flex-wrap: wrap; gap: var(--ui-space-1); }
.offer-tags:empty { display: none; }
.tag-filled, .tag-primary { background: var(--ui-primary-text); border-color: var(--ui-primary-text); color: var(--ui-white); }
.offer-band .tag:not(.tag-filled) { background: var(--ui-white); }
/* QA: "OG CHICKEN COMBOS" lost its S. The italic caps overhang their advance width and the clamp's
   overflow: hidden cut it; the end padding makes room (a word that no longer fits wraps instead),
   and the bottom padding keeps the clamp off the last line's glyphs. */
.offer-title { font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: var(--t-h4); line-height: 1; overflow-wrap: break-word;
    padding-right: .15em; padding-bottom: .1em; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.offer-price { font-weight: 400; }
.offer-window { font-size: 12px; line-height: 16px; font-weight: 400; }
.offer-band .offer-window { color: var(--ui-grey-200); }
@media (hover: hover) { .offer-card:hover .offer-title { color: var(--ui-primary); } }

/* The home carousel card (promo-card-spacing-vertical-stripes): a white 3:4 card; the cut-out stands
   in front of three columns of its own word in vertical red Stripes, read bottom to top. */
.offer-stripes .offer-media { background: var(--ui-white); }
.offer-stripes .offer-media-cutout { aspect-ratio: 3 / 4; }
.offer-vstripes { position: absolute; inset: 0; display: flex; justify-content: space-between; pointer-events: none; }
.offer-vstripes > span { writing-mode: vertical-rl; transform: rotate(180deg); white-space: nowrap; overflow: hidden;
    font-family: var(--ui-font-display); font-weight: 900; text-transform: uppercase; color: var(--ui-primary); font-size: var(--t-hero); line-height: .9; }
.offer-stripes .offer-media-cutout .offer-img { left: 6%; right: 6%; width: 88%; top: 12%; height: 76%; }

/* Offer detail. The product on a full-width red panel standing in a Bucket Device (Spices, or
   Herbs for a limited-time offer). A limited-time offer's head is on black (KFC's "special" page):
   white title, the headline as a red Serif line over it. */
.offer-detail-black { background: var(--ui-black); color: var(--ui-white); }
.offer-detail-black .breadcrumbs a, .offer-detail-black .breadcrumbs { color: var(--ui-grey-200); }
.offer-detail-black .breadcrumbs [aria-current] { color: var(--ui-white); }
.offer-detail > .page { padding-bottom: var(--w-gap-block); }
.offer-detail-black :focus-visible { outline-color: var(--ui-white); }
.offer-detail .offer-tags { margin: 0 0 var(--ui-space-3); }
.offer-detail-black .tag:not(.tag-filled) { background: var(--ui-white); }
.offer-panel-herbs .offer-bucket { background: var(--ui-accent-1); }
.offer-panel-spices .offer-bucket { background: var(--ui-accent-2); }
/* The black accordion (radius 0, 4px black divider above): a Serif caps label and an arrow. */
.offer-accordion { margin-top: var(--w-gap-section); border-top: 0; padding: 0; background: var(--ui-black); color: var(--ui-white); }
.offer-accordion > summary { display: flex; align-items: center; justify-content: space-between; gap: var(--ui-space-4); min-height: 64px;
    padding: var(--ui-space-3) var(--w-gap-inline); cursor: pointer; list-style: none; }
.offer-accordion > summary::-webkit-details-marker { display: none; }
.offer-accordion > summary h2 { margin: 0; color: var(--ui-white); font-size: var(--t-h3); }
.offer-accordion > summary .icon { color: var(--ui-white); transition: transform var(--ui-dur-press) var(--ui-ease-out); }
.offer-accordion[open] > summary .icon { transform: rotate(180deg); }
.offer-accordion > p { margin: 0; padding: 0 var(--w-gap-inline) var(--w-gap-block); color: var(--ui-grey-200); font-size: 14px; line-height: 20px; }
.offer-accordion :focus-visible { outline-color: var(--ui-white); }

/* Promotion detail (storefront/info/promotion): KFC's offer detail on the 12-column grid, the head on
   black. Phone/tablet: the picture full-bleed, the text, the Stripes name, the copy, the black
   accordion, the product cards (2 / 3 columns). 1136+: the picture on columns 1-7 bleeding to the
   left edge of the screen, the text on 8-12; the Stripes name under both, off the right edge; the
   copy on 1-7 beside the accordion on 9-12; the cards four across. */
.promo-hero { background: var(--ui-black); color: var(--ui-white); overflow: hidden; }
.promo-hero-grid { display: grid; padding-bottom: var(--w-gap-section); }
.promo-visual { position: relative; overflow: hidden; margin: 0 calc(-1 * var(--ui-grid-margin)); aspect-ratio: 4 / 3; max-height: 70vh; }
.promo-visual-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.promo-visual-cutout { background: var(--ui-primary); }
.promo-visual-cutout .offer-bucket { left: 50%; right: auto; width: min(64%, 520px); transform: translateX(-50%); top: 24%; bottom: 0; }
.promo-visual-cutout img { position: absolute; left: 8%; width: 84%; top: 6%; height: 90%; object-fit: contain; }
.promo-text { padding-top: var(--w-gap-block); min-width: 0; }
.promo-hero .breadcrumbs, .promo-hero .breadcrumbs a { color: var(--ui-grey-200); }
.promo-hero .breadcrumbs [aria-current] { color: var(--ui-white); }
.promo-hero :focus-visible { outline-color: var(--ui-white); }
.promo .offer-tags { margin: 0 0 var(--ui-space-3); }
.promo-hero .tag:not(.tag-filled) { background: var(--ui-white); }
.promo-title { margin: 0 0 var(--ui-space-4); color: var(--ui-white); font-size: var(--t-h1); overflow-wrap: break-word; }
.promo-price { margin: 0 0 var(--ui-space-3); font-size: 20px; line-height: 24px; font-weight: 400; }
.promo-summary { margin: 0 0 var(--ui-space-3); max-width: 48ch; color: var(--ui-grey-200); }
.promo-ends { margin: 0; font-size: 14px; line-height: 20px; color: var(--ui-grey-200); }
.promo-actions { margin: var(--w-gap-block) 0 0; }
/* The Stripes name, Hero-XL, running off the right edge of the screen (the band clips it there). */
.promo-stripes { font-size: var(--t-hero-xl); margin-top: var(--w-gap-section); }
.promo-body { display: grid; gap: var(--w-gap-section); padding-top: var(--w-gap-section); }
.promo-body .offer-accordion { margin-top: 0; }
.promo-grab { padding-top: var(--w-gap-section); }
.promo-grab-title { margin: 0 0 var(--w-gap-block); }
.promo-back { padding-top: var(--w-gap-section); padding-bottom: var(--w-gap-section); margin-bottom: 0; }
@media (min-width: 600px) {
    .promo-visual { aspect-ratio: 16 / 9; }
    .promo-visual-cutout { aspect-ratio: 4 / 3; max-height: 560px; }
}
@media (min-width: 1136px) {
    .promo-hero-grid { grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--ui-grid-gutter); align-items: center; }
    /* To the left edge of the SCREEN at any width: the grid margin plus whatever the page max leaves. */
    .promo-visual { grid-column: 1 / span 7; margin: 0 0 0 calc(-1 * var(--ui-grid-margin) - max(0px, (100vw - var(--ui-page-max)) / 2));
        aspect-ratio: 4 / 3; max-height: 680px; }
    .promo-visual-cutout { max-height: 680px; }
    .promo-text { grid-column: 8 / -1; padding: var(--w-gap-section) 0 0 var(--w-gap-block); align-self: center; }
    .promo-title { font-size: var(--t-h1); }
    .promo-stripes { grid-column: 1 / -1; }
    .promo-body { grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--ui-grid-gutter); align-items: start; padding-top: var(--ui-space-14); }
    .promo-copy { grid-column: 1 / span 7; }
    .promo-body .offer-accordion { grid-column: 9 / -1; }
    .promo-grab { padding-top: var(--ui-space-14); }
    /* Fewer than four items: three across, so one or two cards are not lost in a row of four. */
    .promo-grab .product-grid:not(:has(> li:nth-child(4))) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ------------------------------------------------------------------ order status (KFC ui-motion 21)
   The stage: black, the status huge in Serif caps (white), the order heading as the red overline.
   processing: the step percentage, and Brand Red rising from the foot to that height (the video's
   black-to-red fill; transform only). done: all Brand Red, KFC's closing line. */
.order-stage { position: relative; overflow: hidden; background: var(--ui-black); color: var(--ui-white); padding: var(--ui-space-10) 0 var(--ui-space-12); }
.order-stage .wrap { position: relative; }
.order-stage-fill { position: absolute; inset: 0; background: var(--ui-primary); transform-origin: 50% 100%; transform: scaleY(0); }
.order-stage-processing .order-stage-fill { transform: scaleY(calc(var(--fill, 0%) / 100%)); }
.motion-ok .order-stage-fill { transition: transform 900ms var(--ui-ease-out); }
.order-stage-done { background: var(--ui-primary); }
.order-stage-stopped { background: var(--ui-grey-800); }
.order-stage-over { margin: 0 0 var(--ui-space-1); font-size: var(--t-h4); color: var(--ui-primary); }
.order-stage-processing .order-stage-over, .order-stage-done .order-stage-over { color: var(--ui-white); }
.order-stage-when { margin: 0 0 var(--w-gap-block); font-size: 14px; line-height: 20px; color: var(--ui-grey-200); }
.order-stage-done .order-stage-when { color: var(--ui-white); }
.order-stage-title { margin: 0; font-size: var(--t-h1); line-height: 1; color: var(--ui-white); overflow-wrap: anywhere; }
.order-stage-pct { margin: var(--ui-space-3) 0 0; font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; font-size: var(--t-h4); line-height: 1; }
.order-stage-pct[hidden] { display: none; }
.order-stage-note { margin: var(--ui-space-3) 0 0; color: var(--ui-grey-200); }
.order-stage .notice { margin-top: var(--ui-space-3); }
.order-stage-enjoy { margin: var(--w-gap-block) 0 var(--ui-space-2); font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase;
    font-size: var(--t-h1); line-height: 1; max-width: 10ch; }
.order-stage .status-motion { margin-top: var(--w-gap-block); }
.order-stage :focus-visible { outline-color: var(--ui-white); }
/* Word by word: each word fades in grey, then turns white (ui-motion 21). */
@keyframes kfc-word { 0% { opacity: 0; color: var(--ui-grey-500); } 60% { opacity: 1; color: var(--ui-grey-500); } 100% { opacity: 1; color: inherit; } }
.motion-ok .kfc-word { animation: kfc-word 360ms var(--ui-ease-out) both; animation-delay: calc(var(--i, 0) * 120ms); }
/* A sting (transition_1 on payment, transition_2 on ready): over the page, once, then removed. */
.order-sting { position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center; background: var(--ui-black); pointer-events: none; }
.order-sting .kfc-motion { width: min(100vw, 56.25vh); }
/* The Stripes wall (video 21): "PREPARING YOUR ORDER" repeated in red on white, rotated, sweeping
   across the screen once as the restaurant accepts the order. Stripes at Hero size (stated floor). */
.stripes-wall { position: fixed; inset: 0; z-index: 41; overflow: hidden; background: var(--ui-white); pointer-events: none; }
.stripes-wall[hidden] { display: none; }
.stripes-wall-inner { position: absolute; left: -60%; top: -60%; width: 220%; height: 220%; display: flex; flex-direction: column; justify-content: center;
    transform: rotate(-68deg); }
.stripes-wall-inner span { display: block; white-space: nowrap; font-family: var(--ui-font-display); font-weight: 900; text-transform: uppercase;
    color: var(--ui-primary); font-size: var(--t-hero); line-height: .9; }
.stripes-wall-inner span:nth-child(even) { margin-left: -1.2em; }
@keyframes kfc-wall { from { transform: translateX(0); opacity: 1; } 80% { opacity: 1; } to { transform: translateX(-30vw); opacity: 0; } }
.stripes-wall.is-running { animation: kfc-wall 1400ms var(--ui-ease-standard) both; }
/* "Earn with KFC Rewards" (video 21): a white card with the expressive heart, the rewards page's words. */
.order-rewards { display: flex; align-items: center; gap: var(--ui-space-4); margin-top: var(--w-gap-section); padding: var(--w-gap-inline);
    border: var(--ui-border-100) solid var(--ui-grey-200); border-radius: var(--ui-radius-100); color: var(--ui-text); text-decoration: none; }
.order-rewards .xicon { width: 40px; height: 40px; color: var(--ui-primary); flex: none; }
.order-rewards strong { display: block; font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; }
.order-rewards:hover { border-color: var(--ui-grey-900); }
.order-all { margin-top: var(--w-gap-block); }

/* A promo card in the run of the menu (video 20): the photo 4:5 on a phone and 2:1 from 600px, the
   tag and the headline on it in white Serif caps (a soft shadow, not a box), a red square arrow
   bottom right. Radius 0 (a card in the listing). */
.plp-promo { position: relative; display: block; margin: var(--w-gap-section) 0 0; overflow: hidden; color: var(--ui-white); text-decoration: none; border-radius: var(--ui-radius-none); }
.plp-promo img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover; }
@media (min-width: 600px) { .plp-promo img { aspect-ratio: 2 / 1; } }
.plp-promo-text { position: absolute; left: var(--w-gap-inline); top: var(--w-gap-inline); right: var(--ui-space-16); display: flex; flex-direction: column; align-items: flex-start; gap: var(--ui-space-2);
    text-shadow: var(--ui-shadow-on-photo); }
.plp-promo-title { font-family: var(--ui-font-heading); font-style: italic; font-weight: 900; text-transform: uppercase; font-size: var(--t-h2); line-height: 1; max-width: 10ch; }
.plp-promo .tag { text-shadow: none; }
.plp-promo-go { position: absolute; right: var(--w-gap-inline); bottom: var(--w-gap-inline); display: inline-flex; align-items: center; justify-content: center;
    width: var(--w-tap-inline); height: var(--w-tap-inline); background: var(--ui-primary); border-radius: var(--ui-radius-40); color: var(--ui-white); }
.plp-promo:focus-visible { outline-offset: 4px; }

