/* ==========================================================================
   ADITYA FOOD — DESKTOP LAYER
   --------------------------------------------------------------------------
   Read this before editing anything, because the safety of the whole file
   depends on two rules that are easy to break by accident.

   RULE 1 — EVERY layout rule lives inside @media (min-width: 1024px).
   The frontend contains ZERO media queries (verified across all 17 pages).
   The 480px phone design in style.css is therefore the base, UNCONDITIONAL
   style, and a min-width query physically cannot match on a phone. That is
   the guarantee that the mobile UI is untouched: not caution, structure.

   RULE 2 — Every rule is scoped under `html.desktop-mode` or
   `html.phone-frame`. Two reasons, both load-bearing:
     a) Specificity. Pages link style.css and then open an inline <style>
        (index.html:12 then :13), so page rules win at equal specificity and a
        plain desktop.css link would lose to them. A class on <html> beats a
        bare class selector, so scoping wins on specificity, not on order.
     b) Failure containment. The classes are only ever added by desktop.js.
        If that script 404s or throws, no class is added, no rule below
        matches, and the site is exactly the mobile site it is today. The
        desktop layer cannot take the live site down with it.

   Do not add an unscoped rule to this file. If a selector here looks like it
   needs to be global, it belongs in style.css instead.
   ========================================================================== */

/* ── Desktop palette ──
   The mobile brand orange is #E8401C (style.css:3). The desktop spec calls for
   #FF4B2B. They are adjacent oranges, so the two modes read as one brand, but
   they are NOT the same value — if the toggle ever makes the app look like it
   changed colour, this is why. --af-primary is what desktop chrome uses;
   --af-primary-app stays #E8401C for anything that must match the mobile app
   exactly (prices, the cart total), so a price never shifts hue between modes.

   Declared on .phone-frame as well, because phone mode still needs the tokens
   for the page furniture that sits outside the mobile column. Inside the
   min-width query like everything else: custom properties are inert until
   something reads them, but there is no reason to publish them on a phone. */
@media (min-width: 1024px) {
html.desktop-mode,
html.phone-frame {
  --af-primary: #FF4B2B;
  --af-primary-2: #FF6A3D;
  --af-accent: #FFB703;
  --af-success: #22C55E;
  --af-bg: #F7F8FC;
  --af-card: #FFFFFF;
  --af-text: #172033;
  --af-text-2: #64748B;
  --af-border: #E5E7EB;
  --af-primary-app: #E8401C;

  --af-r-sm: 8px;
  --af-r: 12px;
  --af-r-lg: 16px;
  --af-r-xl: 22px;
  --af-sidebar-w: 244px;
  --af-shadow-1: 0 1px 2px rgba(23,32,51,.05), 0 1px 3px rgba(23,32,51,.04);
  --af-shadow-2: 0 4px 12px rgba(23,32,51,.07);
  --af-shadow-3: 0 12px 32px rgba(23,32,51,.11);
  --af-ring: 0 0 0 3px rgba(255,75,43,.14);
  --af-ease: cubic-bezier(.4,0,.2,1);
}
}

/* ==========================================================================
   PHONE PREVIEW — the real mobile UI, shown at its own width
   --------------------------------------------------------------------------
   This is NOT a device mockup, and it must not quietly become one again. An
   earlier draft put the 480px <body> inside a thick black bezel with a notch
   on a dark stage, which read as a fake phone rather than as this website.

   The actual requirement is stricter and simpler: reproduce the existing
   mobile page on a laptop, untouched, centred, on a light backdrop. So there
   is no bezel, no notch, no border-radius, no device caption and no background
   of our own design. style.css's own 480px body clamp does the centring and
   every pixel inside that column is produced by the mobile CSS this app
   already ships. Nothing in this block restyles a mobile element.

   Light neutral rather than white, so the column is legible as a column
   without needing a border around it.
   ========================================================================== */
@media (min-width: 1024px) {
  html.phone-frame { background: #E9EDF3; min-height: 100vh; }

  /* A soft shadow is the ONLY thing separating the column from the backdrop.
     A border or a corner radius here would start reading as a device frame. */
  html.phone-frame body { box-shadow: 0 10px 40px rgba(23, 32, 51, .13); }

  /* The nodes desktop.js injects are styled ONLY under .desktop-mode, so in
     phone mode they degrade to unstyled block elements — which would render
     the sidebar's links as a stray list inside the mobile page flow. Hide
     them by name. The toggle is deliberately absent from this list: it has to
     stay reachable in phone mode, that is the point of it. */
  html.phone-frame .af-side,
  html.phone-frame .af-pubhead,
  html.phone-frame .af-authside { display: none !important; }
}

/* ==========================================================================
   THE REAL WORK — everything below is desktop-only
   ========================================================================== */
@media (min-width: 1024px) {

  html.desktop-mode {
    background: var(--af-bg);
    /* Inter for desktop. Falls back to the system stack the mobile UI already
       uses, so an offline/blocked CDN changes nothing structurally. */
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  }

  /* ── 1. The unclamp. This one declaration is the whole redesign ── */
  html.desktop-mode body {
    max-width: none;          /* kills style.css:46 */
    margin: 0;
    padding-left: var(--af-sidebar-w);
    background: var(--af-bg);
    color: var(--af-text);
    min-height: 100vh;
    font-size: 15px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
  }

  /* ── 1b. Public pages get no sidebar, so they must not reserve room for one.
     Keeping the 244px gutter here would push every auth form 244px right of
     where it is centred, which is most of what made the desktop login look
     wrong. ── */
  html.desktop-mode.af-public body { padding-left: 0; }

  /* Injected nodes follow the chrome STATE, not the injection event. A logout
     or a login that happens without a page load — or a resize re-running apply()
     after af_token changed — would otherwise leave a node injected under the old
     state still rendering under the new one, which is how a signed-out visitor
     ends up staring at a rail full of My Orders and Logout. */
  html.desktop-mode.af-public .af-side { display: none !important; }
  html.desktop-mode.af-app .af-pubhead,
  html.desktop-mode.af-app .af-authside { display: none !important; }

  /* Real scrollbar. style.css:57 sets width/height 0, which is right for a
     phone (no scrollbar chrome) and wrong for a pointer device. */
  html.desktop-mode ::-webkit-scrollbar { width: 11px; height: 11px; }
  html.desktop-mode ::-webkit-scrollbar-track { background: transparent; }
  html.desktop-mode ::-webkit-scrollbar-thumb {
    background: #CFD4DC; border-radius: 99px; border: 3px solid var(--af-bg);
  }
  html.desktop-mode ::-webkit-scrollbar-thumb:hover { background: #AEB6C2; }

  /* ── 2. Sidebar (markup injected by desktop.js) ── */
  html.desktop-mode .af-side {
    position: fixed; top: 0; left: 0; bottom: 0; width: var(--af-sidebar-w);
    background: var(--af-card);
    border-right: 1px solid var(--af-border);
    display: flex; flex-direction: column;
    padding: 16px 14px 14px;
    z-index: 900;
    overflow-y: auto;
  }
  html.desktop-mode .af-brand {
    display: flex; align-items: center; gap: 11px;
    padding: 0 8px 15px; margin-bottom: 5px;
    border-bottom: 1px solid var(--af-border);
  }
  html.desktop-mode .af-brand img {
    width: 38px; height: 38px; border-radius: 11px; object-fit: cover;
    box-shadow: 0 3px 10px rgba(255,75,43,.3);
  }
  html.desktop-mode .af-brand b { font-size: 16px; font-weight: 800; letter-spacing: -.3px; }
  html.desktop-mode .af-brand span { display: block; font-size: 11px; color: var(--af-text-2); font-weight: 600; }

  /* The rail grew from 10 items to 13 when the feature list was filled out, and
     at the old rhythm it needed 848px of column in a 768px viewport — so Logout,
     the last item, sat below the fold and the rail had to be scrolled to reach
     it. A nav rail you have to scroll to log out of is broken. These four
     trims are 78px: enough to fit 13 items plus brand, three group labels and
     the footer on a 1366x768 laptop without scrolling, which is the commonest
     laptop there is. Nothing is hidden — .af-side keeps overflow-y:auto for
     genuinely short windows. */
  html.desktop-mode .af-navlabel {
    font-size: 10.5px; font-weight: 800; letter-spacing: .09em;
    text-transform: uppercase; color: #9AA4B2;
    padding: 11px 10px 5px;
  }
  html.desktop-mode .af-nav {
    display: flex; align-items: center; gap: 11px;
    padding: 8px 11px; border-radius: var(--af-r-sm);
    color: var(--af-text-2); text-decoration: none;
    font-size: 14px; font-weight: 600; cursor: pointer;
    /* Logout is a <button> sharing this class with the <a> nav items, so the UA
       button defaults have to be neutralised or it renders in the system font
       with its own background and border. */
    width: 100%; border: 0; background: transparent;
    font-family: inherit; text-align: left;
    transition: background .16s var(--af-ease), color .16s var(--af-ease);
  }
  html.desktop-mode .af-nav .ic { font-size: 17px; width: 20px; text-align: center; flex-shrink: 0; }
  html.desktop-mode .af-nav:hover { background: #F1F3F7; color: var(--af-text); }
  html.desktop-mode .af-nav.active {
    background: rgba(255,75,43,.1); color: var(--af-primary-app); font-weight: 700;
  }
  html.desktop-mode .af-nav .af-pill {
    margin-left: auto; background: var(--af-primary-app); color: #fff;
    font-size: 10.5px; font-weight: 800; padding: 2px 7px; border-radius: 999px;
  }
  html.desktop-mode .af-side-foot {
    margin-top: auto; padding-top: 12px; border-top: 1px solid var(--af-border);
    font-size: 11.5px; color: #9AA4B2; padding-left: 10px;
  }

  /* ── 2b. Public header (markup injected by desktop.js) ──
     The application sidebar is an inside-the-app affordance: it lists My Orders,
     Rewards and Cart, none of which mean anything to someone who has not signed
     in yet. So the signed-out landing page gets a conventional marketing header
     instead — brand, a few links, and the two auth buttons.

     Only injected on the landing page. Every other signed-out page either is an
     auth screen (which brands itself) or redirects to login within a tick, and
     duplicating a header above their existing .top-nav would be noise. */
  html.desktop-mode .af-pubhead {
    position: sticky; top: 0; z-index: 800;
    display: flex; align-items: center; gap: 30px;
    background: rgba(255, 255, 255, .88);
    backdrop-filter: saturate(1.7) blur(12px);
    border-bottom: 1px solid var(--af-border);
    padding: 0 34px; height: 66px;
  }
  html.desktop-mode .af-pub-brand {
    display: flex; align-items: center; gap: 10px;
    text-decoration: none; color: var(--af-text); flex-shrink: 0;
  }
  html.desktop-mode .af-pub-brand img {
    width: 34px; height: 34px; border-radius: 10px; object-fit: cover;
    box-shadow: 0 3px 10px rgba(255, 75, 43, .28);
  }
  html.desktop-mode .af-pub-brand span { font-size: 16.5px; font-weight: 800; letter-spacing: -.3px; }

  html.desktop-mode .af-pubnav { display: flex; align-items: center; gap: 4px; }
  html.desktop-mode .af-pubnav a {
    padding: 8px 14px; border-radius: var(--af-r-sm);
    color: var(--af-text-2); text-decoration: none;
    font-size: 14.5px; font-weight: 600;
    transition: background .16s var(--af-ease), color .16s var(--af-ease);
  }
  html.desktop-mode .af-pubnav a:hover { background: #F1F3F7; color: var(--af-text); }

  html.desktop-mode .af-pubauth { display: flex; align-items: center; gap: 10px; margin-left: auto; }
  html.desktop-mode .af-pub-btn {
    padding: 10px 20px; border-radius: 999px;
    font-size: 14px; font-weight: 700; text-decoration: none;
    transition: filter .16s var(--af-ease), box-shadow .16s var(--af-ease),
                background .16s var(--af-ease);
  }
  html.desktop-mode .af-pub-btn.ghost {
    background: #F1F3F7; color: var(--af-text);
  }
  html.desktop-mode .af-pub-btn.ghost:hover { background: #E4E8EE; }
  html.desktop-mode .af-pub-btn.solid {
    background: linear-gradient(135deg, var(--af-primary) 0%, var(--af-primary-2) 100%);
    color: #fff; box-shadow: 0 4px 14px rgba(255, 75, 43, .3);
  }
  html.desktop-mode .af-pub-btn.solid:hover { filter: brightness(1.05); }
  html.desktop-mode .af-pub-btn:focus-visible { outline: 2px solid var(--af-primary); outline-offset: 2px; }

  /* index.html already has a .topbar inside the orange hero carrying the same
     two auth buttons. Leaving both on screen means two Log in buttons and two
     sign-up buttons stacked vertically; the injected header replaces it. */
  html.desktop-mode.af-public.af-page-index .topbar { display: none; }

  /* ── 3. Top bar ── */
  html.desktop-mode .top-nav {
    padding: 14px 30px;
    background: rgba(255,255,255,.86);
    backdrop-filter: saturate(1.7) blur(12px);
    border-bottom: 1px solid var(--af-border);
    box-shadow: none;
  }
  html.desktop-mode .top-nav .nav-title { font-size: 19px; font-weight: 800; letter-spacing: -.3px; }
  html.desktop-mode .nav-back {
    width: 38px; height: 38px; background: #F1F3F7; font-size: 17px;
    transition: background .16s var(--af-ease), transform .16s var(--af-ease);
  }
  html.desktop-mode .nav-back:hover { background: #E4E8EE; transform: translateX(-2px); }
  html.desktop-mode .cart-btn { width: 40px; height: 40px; background: #F1F3F7; font-size: 19px; }
  html.desktop-mode .cart-btn:hover { background: #E4E8EE; }

  /* ── 4. Bottom nav → the sidebar replaces it ──
     Hidden ONLY inside .desktop-mode, so if desktop.js ever fails the phone
     bottom nav survives on a desktop-sized screen. */
  html.desktop-mode .bottom-nav { display: none !important; }

  /* ── 5. Page shell ──
     .page is style.css:176 (padding 16px, padding-bottom 96px). The 96px
     existed to clear the fixed bottom nav, which no longer exists here. */
  html.desktop-mode .page {
    max-width: 1320px;
    margin: 0 auto;
    padding: 26px 30px 56px;
  }
  html.desktop-mode .section-title {
    font-size: 21px; font-weight: 800; letter-spacing: -.4px; margin-bottom: 18px;
  }

  /* ── 6. Cards ── */
  html.desktop-mode .card {
    background: var(--af-card);
    border: 1px solid var(--af-border);
    border-radius: var(--af-r-lg);
    box-shadow: var(--af-shadow-1);
    margin-bottom: 18px;
    transition: box-shadow .2s var(--af-ease), transform .2s var(--af-ease),
                border-color .2s var(--af-ease);
  }
  html.desktop-mode .card:hover {
    box-shadow: var(--af-shadow-2); transform: translateY(-2px); border-color: #D8DDE5;
  }
  html.desktop-mode .card-body { padding: 20px; }

  /* ── 7. Buttons ── */
  html.desktop-mode .btn-primary,
  html.desktop-mode .btn-outline {
    /* Phones stretch a button to 100% of a 480px screen, where full-width is
       correct. On a desktop a full-width button is 900px of unusable target, so
       width is released here and re-applied per-form. */
    width: auto;
    min-width: 190px;
    padding: 13px 26px;
    font-size: 15px;
    border-radius: var(--af-r);
    transition: transform .16s var(--af-ease), box-shadow .16s var(--af-ease),
                filter .16s var(--af-ease);
  }
  html.desktop-mode .btn-primary:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 8px 24px rgba(232,64,28,.34);
    filter: saturate(1.06);
  }
  html.desktop-mode .btn-primary:active:not(:disabled) { transform: translateY(0); }
  html.desktop-mode .btn-outline:hover:not(:disabled) { background: var(--af-primary-bg); }
  html.desktop-mode .btn-primary:disabled { transform: none; }

  /* ── 8. Forms ── */
  html.desktop-mode .form-group { margin-bottom: 20px; }
  html.desktop-mode .form-label { font-size: 13px; font-weight: 700; margin-bottom: 8px; color: var(--af-text-2); }
  html.desktop-mode .form-input {
    padding: 13px 15px;
    border-radius: var(--af-r);
    border: 1.5px solid var(--af-border);
    background: var(--af-card);
    font-size: 15px;
    transition: border-color .16s var(--af-ease), box-shadow .16s var(--af-ease);
  }
  html.desktop-mode .form-input:hover { border-color: #CFD4DC; }
  html.desktop-mode .form-input:focus {
    border-color: var(--af-primary); box-shadow: var(--af-ring); outline: none;
  }

  /* ── 9. Badges / status ── */
  html.desktop-mode .badge { padding: 5px 12px; font-size: 12px; letter-spacing: .1px; }

  /* ── 10. Empty / loading states: less dead space on a big screen ── */
  html.desktop-mode .empty-state { padding: 90px 30px; }
  html.desktop-mode .empty-state .empty-icon { font-size: 76px; margin-bottom: 20px; }
  html.desktop-mode .empty-state h3 { font-size: 20px; margin-bottom: 10px; }
  html.desktop-mode .loading { padding: 90px 20px; }

  /* ── 11. Toasts: anchored to the content column, not the viewport centre ── */
  html.desktop-mode #toast-container {
    left: auto; right: 26px; transform: none;
    top: 74px; width: 372px; max-width: 372px;
  }
  html.desktop-mode .toast { padding: 14px 17px; font-size: 14px; }

  /* ── 12. Time slots ── */
  html.desktop-mode .time-slot { padding: 10px 17px; font-size: 13.5px; border-radius: 10px; }
  html.desktop-mode .time-slot:hover:not(.disabled) { border-color: var(--af-primary); }
  html.desktop-mode .time-slot.active { box-shadow: var(--af-ring); }

  /* ── 13. Info box ── */
  html.desktop-mode .info-box {
    border-radius: var(--af-r); padding: 14px 17px; font-size: 13.5px;
    border-left: 4px solid var(--af-primary-app);
  }

  /* ── 14. Star rating: phones use 34px stars, desktops want a tighter target ── */
  html.desktop-mode .star { font-size: 27px; transition: transform .14s var(--af-ease); }
  html.desktop-mode .star:hover { transform: scale(1.14); }
  html.desktop-mode .star-row { gap: 5px; margin: 16px 0; }

  /* ── 15. Card grids — REAL containers, verified against the markup ──
     These three ids were read out of the pages, not guessed. They are the
     highest-leverage rules in the file: canteens, menu items and order cards all
     become multi-column without touching a single template.
       #cgrid  canteens.html:97   .c-grid  (already a 2-col grid on mobile)
       #mlist  menu.html:76       holds .food-card
       #olist  my-orders.html:99  holds .ocard                                  */
  html.desktop-mode #cgrid {
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 20px;
  }
  html.desktop-mode #mlist,
  html.desktop-mode #olist {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: 20px;
    align-items: start;
  }
  /* menu.html:23 makes .food-card a horizontal flex row (image left, text right),
     which is right for a 480px screen and wrong in a grid cell. Stack it. */
  html.desktop-mode .food-card {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0;
    overflow: hidden;
    margin-bottom: 0;
    border: 1px solid var(--af-border);
    border-radius: var(--af-r-lg);
    box-shadow: var(--af-shadow-1);
    transition: box-shadow .2s var(--af-ease), transform .2s var(--af-ease);
  }
  html.desktop-mode .food-card:hover {
    transform: translateY(-3px); box-shadow: var(--af-shadow-2);
  }
  html.desktop-mode .food-card .fc-ph,
  html.desktop-mode .food-card .fc-img { width: 100%; height: 168px; object-fit: cover; }
  html.desktop-mode .food-card .fc-info { padding: 16px; }
  html.desktop-mode .food-card .fc-action { padding: 0 16px 16px; }

  /* my-orders.html:23 — .ocard is already a card; give it the desktop skin and
     let the inner rows breathe. */
  html.desktop-mode .ocard {
    margin-bottom: 0;
    border: 1px solid var(--af-border);
    border-radius: var(--af-r-lg);
    box-shadow: var(--af-shadow-1);
    transition: box-shadow .2s var(--af-ease), transform .2s var(--af-ease);
  }
  html.desktop-mode .ocard:hover { transform: translateY(-2px); box-shadow: var(--af-shadow-2); }
  html.desktop-mode .oc-body { padding: 18px 20px; }
  html.desktop-mode .oc-total { font-size: 17px; font-weight: 800; }

  /* ── 16. Hero (index.html:14-40 is a phone-shaped full-screen hero) ──
     index.html:17 is `.hero{min-height:100vh}` — on a phone that is the whole
     point, the hero IS the screen. On a 1080p laptop it means the fold shows a
     logo, a name and a tagline and nothing else, so every real feature on the
     landing page (the five feature cards, the two CTAs) is below the scroll.
     Measured at 1062x670 the hero band was 388px and the feature grid ended at
     y=686 — off-screen. These rules bring the whole hero band plus the feature
     grid inside the fold on a 1366x768 laptop, which is the commonest laptop
     there is, without touching a single mobile value. */
  html.desktop-mode .hero { min-height: auto; }
  html.desktop-mode .hero-bg {
    /* width:100% is load-bearing, not decoration. .hero is a COLUMN flex
       container (index.html:15), and in a flex container an auto cross-axis
       margin CANCELS align-items:stretch — so `margin:0 auto` alone made this
       shrink-to-fit its text at 359px and centre itself, leaving a coloured
       band floating in the middle of an 808px row. An explicit width puts the
       size back; the auto margin then centres the capped 1320px on wide screens
       without affecting the stretch. */
    width: 100%;
    padding: 30px 40px 32px;
    max-width: 1320px; margin: 0 auto;
    border-radius: 0 0 var(--af-r-xl) var(--af-r-xl);
  }
  html.desktop-mode .hero-logo { width: 60px; height: 60px; margin-bottom: 10px; }
  html.desktop-mode .hero-name { font-size: 32px; }
  html.desktop-mode .hero-tagline { font-size: 15px; margin-top: 5px; }
  /* index.html:62 puts a literal <br/> between the college line and the pickup
     window, so the two pills sit on separate lines. On a wide screen there is
     room for both, and one line is two fewer lines of scrolling. */
  html.desktop-mode .hero-clg,
  html.desktop-mode .hero-timing { margin-top: 9px; }
  html.desktop-mode .hero-bg br { display: none; }
  /* With the <br/> gone the two pills would sit flush against each other, so
     they need a real gap. Both are inline-flex, so a margin on the second one
     is enough — no wrapper element required. */
  html.desktop-mode .hero-timing { margin-left: 8px; }

  html.desktop-mode .hero-body { padding: 26px 40px 34px; }
  html.desktop-mode .topbar { max-width: none; padding: 20px 30px; }
  /* A wrapping flex row was fine for 5 boxes and falls apart at 12: `flex: 1 1
     232px` distributes the slack, so the last row is either two boxes stretched
     across the full width or a ragged remainder — measured 5/5/2 at 1366 and 3
     per row at 1024, where the block ran 63px past the fold.

     An explicit grid makes the shape deterministic: 12 divides evenly by 2, 3, 4
     and 6, so every breakpoint lands on whole rows with no orphan. Row gap is
     kept tighter than the column gap because these boxes are wide and short —
     matching the gaps would read as a 12-item table rather than a feature grid. */
  html.desktop-mode .feats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 12px 14px;
    margin-bottom: 24px;
  }
  html.desktop-mode .feat {
    padding: 16px 18px; border-radius: var(--af-r-lg);
    border: 1px solid var(--af-border); box-shadow: var(--af-shadow-1);
    transition: transform .2s var(--af-ease), box-shadow .2s var(--af-ease);
  }
  /* Wide screens have room for six across, which also halves the row count. */
  @media (min-width: 1600px) {
    html.desktop-mode .feats { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  }
  /* Narrow laptops: three across, so the description is not squeezed to one word
     per line and the block still clears a 700px-tall viewport. */
  @media (min-width: 1024px) and (max-width: 1279px) {
    html.desktop-mode .feats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  }
  html.desktop-mode .feat:hover { transform: translateY(-3px); box-shadow: var(--af-shadow-2); }


  html.desktop-mode .fi { width: 46px; height: 46px; }

  /* WhatsApp brand mark. Emoji cannot express it — U+1F4E2 is a megaphone, which is
     what the old box showed. `fill: currentColor` lets the official SVG path take
     the tint, and `.wa` sets it to WhatsApp green. The `g` tone still supplies the
     pale tile, so the audit's five-tone whitelist is untouched: this is an extra
     class on an existing tone, not a sixth tone. Desktop-only, like everything else. */
  html.desktop-mode .fi.wa,
  html.desktop-mode .af-fitem .ic.wa { color: #25D366; }
  html.desktop-mode .fi.wa svg,
  html.desktop-mode .af-fitem .ic.wa svg {
    width: 26px; height: 26px; fill: currentColor; display: block;
  }

  html.desktop-mode .ctas { flex-direction: row; }
  html.desktop-mode .cta-main, html.desktop-mode .cta-sec {
    width: auto; flex: 1 1 240px; padding: 16px 28px; font-size: 16px;
  }

  /* ── 17. PER-PAGE LAYOUT ──────────────────────────────────────────────────
     Everything below is keyed off .af-page-<slug>, a class desktop.js writes to
     <html> from location.pathname. Two reasons this is the mechanism and not a
     hand-written class per page:

       1. Correctness. Several pages carry no wrapper of their own. cart.html
          drops .cart-items and .bill-card straight into <body> with no .page,
          so there is no ancestor to select on — the page identity IS the only
          available discriminator. Guessing an ancestor produced the first draft
          of this file, ~110 lines of which matched nothing at all.
       2. Auditability. A selector naming a page can be checked against a real
          file; a selector naming an imagined wrapper cannot. See §17.11.

     Structurally these all prefer re-flowing an EXISTING container into a grid
     over turning <body> itself into one. Re-flowing a container cannot move a
     sibling out from under it; re-flowing body can, and several pages stash
     fixed bars and overlays as direct body children that a body grid would
     start placing into cells. */

  /* ── 17.0  THE FEATURE LIST ───────────────────────────────────────────────
   One markup shape, three surfaces: the login rail (inside the .hero the page
   already has), the signup rail (injected), and the landing page (injected as
   extra .feat boxes). See FEATURES in desktop.js — the copy lives there and is
   pinned to a phrase in a real file by the audit.

   Colours here are white-on-orange because both rails are orange gradients.
   The landing page does NOT use this block: it reuses the page's own .feat
   markup instead, so those boxes inherit .feat/.fi/.ft and stay visually
   identical to the five already on the page.

   Nothing lays out below 1024px, and nothing lays out unstyled in phone mode
   either: .af-fgrid and .af-xfeat both have a top-level default hide near the
   toggle, and desktop.js removes the nodes outright below 1024px. */
  .af-fgrid { display: none; }
  html.desktop-mode .af-fgrid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
    margin: 26px 0 0;
    text-align: left;
  }
  html.desktop-mode .af-fitem { display: flex; gap: 12px; align-items: flex-start; }
  html.desktop-mode .af-fitem .ic {
    font-size: 19px; line-height: 1.25; flex-shrink: 0;
    width: 34px; height: 34px; border-radius: 10px;
    background: rgba(255, 255, 255, .17);
    display: flex; align-items: center; justify-content: center;
  }
  html.desktop-mode .af-fitem .tx { display: block; min-width: 0; }
  html.desktop-mode .af-fitem b {
    display: block; font-size: 14.5px; font-weight: 700; color: #fff;
    letter-spacing: -.1px;
  }
  html.desktop-mode .af-fitem em {
    display: block; font-style: normal; font-size: 12.5px; line-height: 1.42;
    color: rgba(255, 255, 255, .84); margin-top: 2px;
  }

  /* The login rail is 504px wide, so a single column of nine runs off the
     bottom of a 768px laptop. Two columns: nine items become five rows. */
  html.desktop-mode .af-fgrid-wide { grid-template-columns: 1fr 1fr; gap: 15px 20px; margin-top: 30px; }
  html.desktop-mode .af-fgrid-wide .af-fitem b { font-size: 13.5px; }
  html.desktop-mode .af-fgrid-wide .af-fitem em { font-size: 12px; }
  html.desktop-mode .af-fgrid-wide .af-fitem .ic { width: 30px; height: 30px; font-size: 17px; }

  /* Landing-page extras re-use the page's own .feat, so display:flex already
     comes from index.html. Re-stated anyway: it costs one line, and if the page
     ever changes .feats to a grid this keeps the injected boxes honest without
     anyone having to remember. */
  html.desktop-mode .af-xfeat { display: flex; }

  /* 17.1  LOGIN — the only page with a natural two-column split.
          login.html:39-76 is  .page > (.hero, .card), and .hero holds the
          branding (back-bar, img.logo, .htitle, .hsub). So .page becomes the
          grid, .hero the brand panel and .card the form. No markup added.

          The form column is a fixed 420px and deliberately NOT flexible. The
          failure this replaces was a form stretched across whatever the window
          happened to be, which on a 27" display is a 900px-wide login button.
          A fixed measure also means the split holds at every desktop width, so
          there is no narrow-laptop tier that collapses it — at the 1024px
          floor the brand panel still gets 504px, which is enough for a logo
          and two lines of type. login.html has no .top-nav, hence min-height
          100vh rather than 100vh-minus-a-header. */
  html.desktop-mode.af-page-login .page {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 420px;
    gap: 48px;
    align-items: center;
    min-height: 100vh;
    max-width: 1140px;
    margin: 0 auto;
    padding: 44px 30px;
  }
  html.desktop-mode.af-page-login .hero {
    background: linear-gradient(150deg, #E8401C 0%, #FF5733 48%, #FF7043 100%);
    border-radius: var(--af-r-xl);
    padding: 52px 46px;
    box-shadow: 0 18px 46px rgba(232, 64, 28, .26);
    color: #fff;
    text-align: center;
  }
  /* Kept, not hidden — the back arrow is real navigation, and removing it on
     desktop would be removing functionality. Only its chrome is restyled. */
  html.desktop-mode.af-page-login .back-bar {
    background: rgba(255, 255, 255, .16);
    border-radius: var(--af-r);
    padding: 4px;
  }
  /* The logo plate, for both auth rails.

     The uploaded mark is a 672x763 PORTRAIT image that is 93.9% flat white
     canvas — the mark itself occupies x 126-547, y 165-547, which is 5.1% of the
     pixels (measured off the decoded bitmap, not estimated). Rendered into a
     square box with object-fit:cover it is never actually cropped: the crop band
     is y 45-717, which contains the whole of y 165-547. And cover beats contain
     here, because cover scales by width (S/672) while contain scales by height
     (S/763) on a portrait source. So the mark's rendered size is

         0.6265*S wide  x  0.5685*S tall      (S = the box size)

     which means the box is the ONLY lever on legibility, and it was being pulled
     the wrong way: the short-viewport block dropped login to 54px and signup to
     46px, putting the mark at 34x31 and 29x26 on 1366x768 and 1280x720 — the two
     most common laptop screens, and the reason the logo was hard to see.

     The circular crop was the other half of it. A 672x763 rectangle clipped to
     50% is just a smaller, odder logo, and it threw away the white plate the
     source already provides. Rounded-square on white instead, so on the orange
     rail the plate reads as deliberate rather than as leftover background.

     cover is kept over contain deliberately: measured against the content box,
     cover renders the mark at 0.6265*S and contain at only 0.5518*S, so
     switching to contain would have made the logo SMALLER while fixing nothing. */
  html.desktop-mode.af-page-login .logo,
  html.desktop-mode .af-as-logo {
    object-fit: cover;
    object-position: center;
    background: #fff;
    border: 1px solid rgba(255, 255, 255, .5);
    box-shadow: 0 12px 30px rgba(120, 26, 8, .28);
  }

  /* Roomiest case. login 120 and signup 128: marks of 75x68 and 80x73, up from
     55x50 and 48x43. Every one of these sizes was swept in a real browser for
     page overflow AND for the last rail row clearing the rail's bottom padding,
     because .af-authside is position:fixed and so cannot be caught by
     scrollHeight — a clipped rail reads as "no overflow" if you only look there.
     1440x900, 1366x768, 1280x900 and 1600x900 all pass at 128. */
  html.desktop-mode.af-page-login .logo {
    width: 120px; height: 120px; border-radius: 22px; margin: 18px auto 14px;
  }
  html.desktop-mode.af-page-login .htitle { color: #fff; font-size: 34px; letter-spacing: -.7px; }
  html.desktop-mode.af-page-login .hsub { color: rgba(255, 255, 255, .92); font-size: 15px; }
  html.desktop-mode.af-page-login .card { padding: 32px 30px; }
  html.desktop-mode.af-page-login .card h2 { font-size: 24px; font-weight: 800; letter-spacing: -.5px; }
  /* Full width OF THE CARD — not of the page. This is the whole point: the
     button is as wide as the form it submits, which is what the mobile design
     already did inside 480px. §7 released the global 100%; this puts it back
     where it belongs. */
  html.desktop-mode.af-page-login .card .btn-primary,
  html.desktop-mode.af-page-login .card .btn-outline { width: 100%; }

  /* 17.2  SIGNUP — brand rail + compact card.
          signup.html has NO .hero. It is .shdr > (.sh-back, .sh-title), then
          .body > .prog and three .panel steps. So unlike login there is nothing
          already on the page that can become the brand panel, and desktop.js
          injects one.

          It is a fixed left rail plus a body gutter, not a grid child, for the
          reason given at the top of §17: re-flowing a container can displace a
          sibling, and .body holds .prog plus three step panels whose
          visibility page JS toggles. A fixed rail cannot disturb either.

          Keyed off .af-has-rail, which desktop.js writes only when it actually
          injects the element — so a signed-in user who somehow lands on
          signup.html does not get 560px of empty gutter beside a form with no
          rail in it.

          Copy is the shared FEATURES list — the same one the landing page and
          the login rail show — and every entry in it is pinned to a phrase in a
          real file by the audit, so nothing new is asserted about the product. */
  html.desktop-mode.af-has-rail.af-page-signup body { padding-left: 560px; }
  html.desktop-mode.af-has-rail .af-authside {
    position: fixed; top: 0; left: 0; bottom: 0; width: 560px;
    padding: 54px 50px; overflow-y: auto;
    display: flex; flex-direction: column;
    background: linear-gradient(150deg, #E8401C 0%, #FF5733 48%, #FF7043 100%);
    color: #fff;
  }
  /* margin:auto 0 rather than justify-content:center. On a flex column that is
     the difference between "centred, and scrolls if it has to" and "centred, and
     the top is unreachable once it does". A tall rail — nine feature rows plus
     the brand block — overflows a 768px laptop, and justify-content:center
     pushes the overflow past the scroll origin so the logo cannot be scrolled
     back into view. Auto margins collapse to 0 in exactly that case. */
  html.desktop-mode .af-as-in { margin: auto 0; width: 100%; }
  html.desktop-mode .af-as-logo {
    width: 128px; height: 128px; border-radius: 22px;
    margin-bottom: 20px;
  }
  html.desktop-mode .af-as-name { font-size: 30px; font-weight: 800; letter-spacing: -.6px; }
  html.desktop-mode .af-as-tag { font-size: 15px; color: rgba(255, 255, 255, .92); margin-top: 6px; }
  /* The signup rail is 560px, so the list gets two columns for the same reason
     the login rail does: nine rows in one column do not fit a laptop screen. */
  html.desktop-mode.af-has-rail .af-fgrid { grid-template-columns: 1fr 1fr; gap: 15px 22px; margin-top: 30px; }
  html.desktop-mode.af-has-rail .af-fitem b { font-size: 13.5px; }
  html.desktop-mode.af-has-rail .af-fitem em { font-size: 12px; }

  /* Narrow laptops. 1024px is the floor and a 560px rail would leave 464px for
     a 460px card plus its own padding, so the RAIL narrows, not the card. */
  @media (min-width: 1024px) and (max-width: 1279px) {
    html.desktop-mode.af-has-rail.af-page-signup body { padding-left: 400px; }

    /* login's branding text, at the REAL selectors. The short-viewport block
       further down shrinks .hero-logo / .hero-name / .hero-tagline, which are
       the index page's classes — login.html has none of them. Its branding is
       img.logo / .htitle / .hsub, so that block had no effect here and login's
       rail overflowed at 1024x700 by 63px. These are the names the page actually
       uses. Saves 20px + 5px = 25px of text.

       The LOGO is deliberately absent here. This block used to pin it to 54px on
       width alone, which meant a 1024x900 window — plenty of height — got the
       small logo while a 1152x700 window got the large one. Height is what
       constrains the plate, so the logo is sized by the max-height blocks below
       and nothing here. Width still narrows the rail, just not the mark. */
    html.desktop-mode.af-page-login .htitle { font-size: 26px; }
    html.desktop-mode.af-page-login .hsub { font-size: 13px; margin-top: 3px; }
    html.desktop-mode.af-has-rail .af-authside { width: 400px; padding: 34px 32px; }
    html.desktop-mode .af-as-name { font-size: 25px; }

    /* TWO columns here, and the duplicated 1fr rule that stood next to this one
       is gone. It was set to one column on the reasoning that 336px of content
       cannot hold two readable columns. True, and the wrong trade: one column of
       twelve items measures 629px, so at 1024x700 the last four fell below the
       fold and no amount of padding would have helped. Two columns is 157px
       apiece, which is narrow but readable at 12px, and it halves the height.
       Measured after: the grid is 6 rows instead of 12. */
    html.desktop-mode.af-has-rail .af-fgrid {
      margin-top: 22px; grid-template-columns: 1fr 1fr; gap: 12px 16px;
    }
    html.desktop-mode.af-has-rail .af-fitem { gap: 9px; }
    html.desktop-mode.af-has-rail .af-fitem .ic { width: 26px; height: 26px; font-size: 15px; }
    html.desktop-mode.af-has-rail .af-fitem b { font-size: 12.5px; }
    html.desktop-mode.af-has-rail .af-fitem em { font-size: 11px; line-height: 1.35; }
  }

  /* Short viewports: 1280x720 and 1024x700 are the tight laptop cases, and they
     are a HEIGHT problem, not a width one. Every query above is a width query,
     so none of them could have addressed this — a 1280-wide window is not a
     narrow one. Media queries add no specificity, so these win purely by
     coming later in the file at equal specificity. */
  @media (min-width: 1024px) and (max-height: 820px) {
    html.desktop-mode.af-page-login .hero { padding-top: 30px; padding-bottom: 30px; }

    /* login's own classes this time. See the note at 1024-1279 above: the index
       hero classes do not exist on login.html, so these rules were inert. The
       plate goes 120 -> 104 here and 128 -> 112 on signup (marks 65x59 and
       70x64) — it used to be 54 and 46, which put the marks at 34x31 and 29x26
       on the most common laptop screen there is. 112 is the largest signup
       plate that still clears 1280x720; 120 already clips by 1px. */
    html.desktop-mode.af-page-login .logo {
      width: 104px; height: 104px; border-radius: 20px; margin: 10px auto 8px;
    }
    html.desktop-mode.af-page-login .htitle { font-size: 26px; }
    html.desktop-mode.af-page-login .hsub { font-size: 13px; margin-top: 3px; }

    /* The index hero, which does use these names. */
    html.desktop-mode .hero-logo { width: 50px; height: 50px; margin-bottom: 7px; }
    html.desktop-mode .hero-name { font-size: 27px; }
    html.desktop-mode .af-fgrid-wide { margin-top: 20px; gap: 10px 18px; }
    html.desktop-mode.af-has-rail .af-as-logo {
      width: 112px; height: 112px; border-radius: 20px; margin-bottom: 10px;
    }
    html.desktop-mode.af-has-rail .af-as-name { font-size: 22px; }
    html.desktop-mode.af-has-rail .af-fgrid { margin-top: 16px; gap: 9px 14px; }
  }

  /* 700px tall. Swept, not guessed: at 1152x700 the signup rail stops taking a
     plate above 64px (80 already clips the last row by 26px), and login's rail
     is not the binding column there at all — the login CARD is.

     That card overflow was a pre-existing bug, not something the plate caused:
     .card measures a flat 645px at every viewport (it is 645 at 1600x900 as
     well), so at 1280x720 it overflowed the page by 9px and at 1152x700 by 29px
     with the logo hidden entirely. Verified by hiding the logo and re-measuring
     scrollHeight: the overflow did not move. Since the page is a grid whose rows
     are as tall as the taller column, no amount of plate shrinking could have
     fixed it.

     This block trims it. Padding 32 -> 20 (-24), the two .divider margins
     20/20 -> 11/11 (-36 across both), the .ig field gaps 16 -> 10 (-12), the
     intro paragraph 28 -> 16 (-12), the forgot link 20 -> 12 (-8) and the h2
     24px -> 21px (-6): 645 -> 547. Nothing about the form changes — same inputs,
     same buttons, same order, same widths — only vertical air. */
  @media (min-width: 1024px) and (max-height: 740px) {
    html.desktop-mode.af-page-login .logo { width: 72px; height: 72px; border-radius: 16px; }
    html.desktop-mode.af-has-rail .af-as-logo { width: 64px; height: 64px; border-radius: 18px; }

    html.desktop-mode.af-page-login .card { padding: 20px 26px; }
    html.desktop-mode.af-page-login .card h2 { font-size: 21px; }
    html.desktop-mode.af-page-login .card > p { margin-bottom: 16px; }
    html.desktop-mode.af-page-login .card .ig { margin-bottom: 10px; }
    html.desktop-mode.af-page-login .card .forgot { margin-bottom: 12px; }
    html.desktop-mode.af-page-login .card .divider { margin: 11px 0; }
  }

  /* The one genuinely cramped case: a 1024-wide window that is only 700 tall,
     i.e. a half-height window rather than a small laptop. The card trim above
     is not enough here — the rail itself clips its last row by 23px, and it did
     so before any of this work (with the old 54px plate and 30px of bottom
     padding the clip was 25px, so this is not a regression either way). Two
     columns in a 400px rail make each item 74px tall because the description
     wraps to three lines, so the six rows need the room back: row gap 12 -> 8
     (-20 over five gaps) and the description line-height 1.35 -> 1.25 (-6). */
  @media (min-width: 1024px) and (max-width: 1159px) and (max-height: 740px) {
    html.desktop-mode.af-page-login .logo {
      width: 64px; height: 64px; border-radius: 16px; margin: 8px auto 8px;
    }
    html.desktop-mode.af-page-login .hero { padding-bottom: 18px; }
    html.desktop-mode.af-has-rail .af-as-logo { width: 64px; height: 64px; border-radius: 16px; }
    html.desktop-mode.af-has-rail .af-fgrid { row-gap: 8px; }
    html.desktop-mode.af-has-rail .af-fitem em { line-height: 1.25; }

    /* login's rail is NOT .af-has-rail — that class is only ever written when
       desktop.js injects a rail, and login already had a .hero to style, so its
       grid is .af-fgrid-wide and its items are .af-fgrid-wide .af-fitem. The
       two rules above therefore did nothing here, which is why the first
       attempt at this trim left 1024x700 exactly where it started. These are the
       names login actually uses. Row gap 10 -> 7 (-15 over five gaps),
       description 12px -> 11px with a tighter line-height so the three-line wrap
       in a 157px column comes down to two, and the six rows lose 6px each. */
    html.desktop-mode .af-fgrid-wide { margin-top: 14px; row-gap: 7px; }
    html.desktop-mode .af-fgrid-wide .af-fitem em { font-size: 11px; line-height: 1.25; }
    html.desktop-mode.af-page-login .hero { padding-top: 22px; padding-bottom: 12px; }
  }

  /* 1024-1159 wide but TALL (a 1024x900 window). Height is not the problem
     here, width is: the rail is only 400px, so the card and the rail are close
     to the same height and a large plate tips the page into scrolling. Swept:
     104px is the last size that leaves the page unscrolled, 112px overflows by
     22px. 96 keeps 2px of margin. */
  @media (min-width: 1024px) and (max-width: 1159px) and (min-height: 821px) {
    html.desktop-mode.af-page-login .logo {
      width: 96px; height: 96px; border-radius: 20px; margin: 12px auto 10px;
    }
  }

  /* The compact card: 460px, inside the 400-480px band the design calls for.
     The earlier draft used 660px, which is a form with room to spare rather
     than a compact one, and it made the submit button 660px long. */
  html.desktop-mode.af-page-signup .panel,
  html.desktop-mode.af-page-forgot-password .panel {
    max-width: 460px;
    margin: 0 auto;
    padding: 30px 30px 26px;
    border: 1px solid var(--af-border);
    border-radius: var(--af-r-xl);
    box-shadow: var(--af-shadow-2);
  }
  html.desktop-mode.af-page-signup .role-card,
  html.desktop-mode.af-page-signup .role-pick {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 12px;
  }
  /* 100% of the 460px card. Never of the page. */
  html.desktop-mode.af-page-signup .panel .btn-primary,
  html.desktop-mode.af-page-signup .panel .btn-outline,
  html.desktop-mode.af-page-forgot-password .panel .btn-primary,
  html.desktop-mode.af-page-forgot-password .panel .btn-outline { width: 100%; }

  /* signup's and forgot-password's own sticky headers get the same desk chrome
     as .top-nav so the three auth pages read as one set. */
  html.desktop-mode.af-page-signup .shdr,
  html.desktop-mode.af-page-forgot-password .fhdr {
    background: rgba(255, 255, 255, .86);
    backdrop-filter: saturate(1.7) blur(12px);
    border-bottom: 1px solid var(--af-border);
    padding: 14px 30px;
  }
  html.desktop-mode.af-page-signup .sh-title,
  html.desktop-mode.af-page-forgot-password .fh-title {
    font-size: 19px; font-weight: 800; letter-spacing: -.3px;
  }

  /* forgot-password gets a centred card and no rail. It is a three-step
     recovery flow, not a marketing surface — a full-height orange panel beside
     it would be decoration pretending to be information. Same 460px measure as
     signup so the two auth flows match. */
  html.desktop-mode.af-page-forgot-password .body { padding-top: 34px; }

  /* 17.3  CART — the page the desktop layout helps most, and the one with no
          .page wrapper. #cart-content is the existing container, so it becomes
          the grid: items/other-time/delivery/slot in column 1, the bill sticky
          in column 2. Children are placed explicitly because .del-fields is
          shown and hidden by JS and must not shift the bill into the wrong
          row when it appears. */
  html.desktop-mode.af-page-cart #cart-content {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 384px;
    gap: 22px;
    align-items: start;
    max-width: 1320px;
    margin: 0 auto;
  }
  html.desktop-mode.af-page-cart #cart-content > .cart-items,
  html.desktop-mode.af-page-cart #cart-content > .ot-card,
  html.desktop-mode.af-page-cart #cart-content > .del-fields,
  html.desktop-mode.af-page-cart #cart-content > .slot-card { grid-column: 1; }
  html.desktop-mode.af-page-cart #cart-content > .bill-card {
    grid-column: 2;
    grid-row: 1 / span 4;
    position: sticky;
    top: 26px;
    border: 1px solid var(--af-border);
    box-shadow: var(--af-shadow-2);
  }
  html.desktop-mode.af-page-cart #cart-content > .bill-card .btn-primary { width: 100%; }
  /* #pbar is a fixed bottom bar on a phone, and it cannot stay fixed on a laptop.
     The view toggle is 214px wide sitting in the bottom-right corner, so a pay
     button pinned to the bottom edge ends up underneath it and cannot be clicked.
     Making #pbar an ordinary card below the two columns was tried and was worse:
     the cart grid runs ~1400px tall, so #place-btn landed at y=1376 in a 1437px
     document — 522px below the fold at 1440x900 and 722px at 1280x720, with
     nothing on screen pointing at it. Measured, not guessed.

     So on a laptop the bar is dropped entirely and the order button rides
     .bill-card, which is already position:sticky at top:26px in column 2. Sticky
     to the TOP is what makes this safe: the toggle is pinned to the bottom-right,
     so the card and the toggle never share vertical space and never collide. The
     button is on screen at scroll position 0 and at every position after it.
     .js-place-desk is display:none in cart.html's own stylesheet, so this is the
     one rule that turns it on and the phone needs nothing to stay unchanged. */
  html.desktop-mode.af-page-cart #pbar { display: none; }
  html.desktop-mode.af-page-cart #cart-content > .bill-card .js-place-desk {
    display: block;
    width: 100%;
    margin-top: 18px;
  }
  /* The card is sticky, so give it room to breathe rather than sitting flush. */
  html.desktop-mode.af-page-cart #cart-content > .bill-card { padding: 20px; }

  /* 17.3b  THE OTHER PHONE BOTTOM BARS — two more pages pin a bar to the bottom
           of the window, and both are wrong on a laptop for the same reason.

           A bar at `position:fixed; bottom:0; left:50%; translateX(-50%)` is
           centred on the WINDOW. A laptop has a 244px sidebar on the left, so
           that bar slides underneath it.

           Measured on scheduled-order.html: at 1024x700 #pbar spanned x 37..977
           and its "Schedule for Tomorrow" button sat at x 53..297, while the
           sidebar covers x 0..244. elementFromPoint at the button's own centre
           returned a `button.af-nav` — a sidebar nav button. The page's ONLY
           submit action could not be pressed. At 1280x720 the button was at
           x 181..425 with the same 63px underneath the sidebar; it only read as
           "clickable" because its centre happened to clear. At 1440x900 the
           940px cap cleared the sidebar by luck, which is why this only shows up
           on the narrower laptops people actually carry.

           Two different answers, because the two bars are not the same thing.

           (a) .adm-nav — 14 admin/superadmin/delivery pages. It duplicates
               navigation the sidebar already provides: every one of its links is
               present in the sidebar's role group in desktop.js, checked by
               admnav-dupe-check.js (14/14). On a laptop it is a second copy of
               the tab bar, 480px wide, floating over the content - and no page
               reserves space for it. Hide it.

           (b) #pbar on scheduled-order.html — it carries the page's only submit
               action, so it cannot be hidden. Re-anchor it into the content area
               and reserve room at the right for the view toggle, or the toggle
               lands on the button.

           #scbar on menu.html is deliberately not touched: the layer already
           turns it into a static card (§17.5), and it is only revealed by the
           "customise" tap that precedes it, so it is never something a user has
           to go looking for. */
  html.desktop-mode .adm-nav { display: none; }

  html.desktop-mode.af-page-scheduled-order #pbar {
    left: var(--af-sidebar-w);
    right: 0;
    bottom: 0;
    width: auto;
    max-width: none;
    transform: none;
    margin: 0;
    border-radius: 0;
    background: #fff;
    border: 0;
    border-top: 1px solid var(--af-border);
    box-shadow: 0 -8px 26px rgba(15, 23, 42, .10);
    padding: 12px 30px 14px;
    padding-right: calc(var(--af-vt-clear) + 6px);
    z-index: 90;
  }
  html.desktop-mode.af-page-scheduled-order #pbar .pb-row {
    margin: 0 auto 10px;
    max-width: 940px;
  }
  html.desktop-mode.af-page-scheduled-order #pbar .btn-primary {
    display: block;
    margin: 0 auto;
    width: 100%;
    max-width: 420px;
  }

  /* 17.4  CANTEENS — #cgrid is already handled in §15. Here: a wider header, a
          proper search field, and a content measure so the page does not just
          stretch edge to edge on a 2560px monitor. */
  html.desktop-mode.af-page-canteens .hdr,
  html.desktop-mode.af-page-canteens .body { max-width: 1320px; margin: 0 auto; padding-left: 30px; padding-right: 30px; }
  html.desktop-mode.af-page-canteens .hdr-greet { font-size: 28px; font-weight: 800; letter-spacing: -.5px; }
  html.desktop-mode.af-page-canteens .srch-bar {
    padding: 14px 18px;
    border-radius: var(--af-r);
    border: 1.5px solid var(--af-border);
    background: var(--af-card);
    box-shadow: var(--af-shadow-1);
  }
  html.desktop-mode.af-page-canteens .reward-bar,
  html.desktop-mode.af-page-canteens .sb-any {
    border-radius: var(--af-r);
    border: 1px solid var(--af-border);
  }

  /* 17.5  MENU — #mlist is handled in §15. The category strip and the floating
          cart bar both need desktop treatment: the strip gets room, and #scbar
          (fixed to the bottom of a phone screen) becomes a static bar. */
  html.desktop-mode.af-page-menu .mhdr,
  html.desktop-mode.af-page-menu .cats,
  html.desktop-mode.af-page-menu .body,
  html.desktop-mode.af-page-menu #cdesc-bar { max-width: 1320px; margin-left: auto; margin-right: auto; padding-left: 30px; padding-right: 30px; }
  html.desktop-mode.af-page-menu .cats { gap: 10px; padding: 14px 30px; }
  html.desktop-mode.af-page-menu .cat { padding: 10px 18px; font-size: 14px; }
  html.desktop-mode.af-page-menu #scbar {
    position: static;
    max-width: 1320px;
    margin: 20px auto 0;
    border: 1px solid var(--af-border);
    border-radius: var(--af-r-lg);
    box-shadow: var(--af-shadow-1);
  }

  /* 17.6  ORDERS — #olist is handled in §15. Just the measure and the tab
          strip, which is a full-bleed row of tap targets on a phone. */
  html.desktop-mode.af-page-my-orders .ohdr,
  html.desktop-mode.af-page-my-orders .body { max-width: 1320px; margin: 0 auto; padding-left: 30px; padding-right: 30px; }
  html.desktop-mode.af-page-my-orders .ftabs { gap: 10px; padding: 14px 0 18px; }
  html.desktop-mode.af-page-my-orders .ftab { padding: 11px 20px; font-size: 14px; border-radius: 999px; }

  /* 17.7  PROFILE — .body already holds .rbox and the six .mblk sections, so it
          becomes the grid. .rbox is the rewards balance and reads as a
          headline, so it spans the full width above the section cards. */
  html.desktop-mode.af-page-profile .ptop { max-width: 720px; margin: 0 auto; }
  html.desktop-mode.af-page-profile .body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 20px;
    align-items: start;
    max-width: 1180px;
    margin: 0 auto;
  }
  html.desktop-mode.af-page-profile .body > .rbox { grid-column: 1 / -1; }
  html.desktop-mode.af-page-profile .mblk { margin-bottom: 0; }

  /* 17.8  REWARDS — same shape: .body holds .wallet-card plus four
          .section-card blocks. The wallet spans; the rest pair up. */
  html.desktop-mode.af-page-rewards .body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    gap: 20px;
    align-items: start;
    max-width: 1200px;
    margin: 0 auto;
  }
  html.desktop-mode.af-page-rewards .body > .wallet-card,
  html.desktop-mode.af-page-rewards .body > #rewards-disabled-banner { grid-column: 1 / -1; }
  html.desktop-mode.af-page-rewards .section-card { margin-bottom: 0; }
  html.desktop-mode.af-page-rewards .wallet-row { gap: 26px; }

  /* 17.9  SEARCH — .food-row is a horizontal row with an image, a name, a price
          and quantity controls. In a grid cell that row has no room to breathe,
          so results stay a list, widened, with the trending tiles above going
          multi-column. */
  html.desktop-mode.af-page-search .srch-hdr { padding: 18px 30px; }
  html.desktop-mode.af-page-search .body { max-width: 1000px; margin: 0 auto; padding: 24px 30px 56px; }
  html.desktop-mode.af-page-search .srch-wrap {
    padding: 15px 20px;
    border-radius: var(--af-r);
    border: 1.5px solid var(--af-border);
    box-shadow: var(--af-shadow-1);
  }
  html.desktop-mode.af-page-search #trending {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 14px;
  }
  html.desktop-mode.af-page-search .food-row {
    background: var(--af-card);
    border: 1px solid var(--af-border);
    border-radius: var(--af-r);
    margin-bottom: 12px;
    padding: 14px 18px;
    box-shadow: var(--af-shadow-1);
    transition: box-shadow .2s var(--af-ease), transform .2s var(--af-ease);
  }
  html.desktop-mode.af-page-search .food-row:hover { transform: translateY(-2px); box-shadow: var(--af-shadow-2); }
  html.desktop-mode.af-page-search .fr-img { width: 62px; height: 62px; border-radius: var(--af-r-sm); }

  /* 17.10  REMAINING SINGLE-COLUMN PAGES — payment, confirmation, group order,
           scheduled order and coming-soon are all forms or receipts. A form at
          1400px wide is worse to read than one at 480px, so these get a
          comfortable measure and roomier cards, not columns. */
  /* The `padding` SHORTHAND here was silently deleting the sidebar gutter.
     §1 sets `html.desktop-mode body { padding-left: var(--af-sidebar-w) }` at
     specificity (0,1,2), but this selector is `html.desktop-mode.af-page-X body`
     at (0,2,2) — so the shorthand's implied padding-left:30px WON. Measured on
     group-order.html: sidebar 244px wide, body padding-left 30px, so 214px of
     every page rendered underneath the rail. That is the whole of "the text is
     not visible, it is too far to the left": the "⏰ Order closes in" label
     starts at x=46, the first timer chip's text at x=234, and the Create Group
     Order button ran 46→263 — all of it behind an opaque white panel. Fixed by
     restating the gutter after the shorthand so the intent is explicit and no
     longer depends on which selector happens to outrank which. */
  html.desktop-mode.af-page-payment body,
  html.desktop-mode.af-page-confirmation body,
  html.desktop-mode.af-page-group-order body,
  html.desktop-mode.af-page-scheduled-order body,
  html.desktop-mode.af-page-coming-soon body {
    padding: 26px 30px 56px;
    padding-left: var(--af-sidebar-w);
  }

  /* Measured by real class name rather than `> div:not(#toast-container)`. Those
     five pages wrap their content in differently-named elements (.phdr/.conf-hero/
     .ghdr/.shdr/.chdr + .body), so one structural guess cannot cover them all —
     and a guess that silently matches nothing is worse than no rule, because it
     reads as "styled" while doing nothing. Verified against the markup. */
  html.desktop-mode.af-page-payment .phdr,
  html.desktop-mode.af-page-payment .body,
  html.desktop-mode.af-page-confirmation .conf-hero,
  html.desktop-mode.af-page-confirmation .body,
  html.desktop-mode.af-page-group-order .ghdr,
  html.desktop-mode.af-page-group-order .body,
  html.desktop-mode.af-page-scheduled-order .shdr,
  html.desktop-mode.af-page-scheduled-order .body,
  html.desktop-mode.af-page-scheduled-order .pbar,
  html.desktop-mode.af-page-coming-soon .chdr,
  html.desktop-mode.af-page-coming-soon .body {
    max-width: 940px;
    margin-left: auto;
    margin-right: auto;
  }
  html.desktop-mode.af-page-payment .sum-card,
  html.desktop-mode.af-page-confirmation .status-card,
  html.desktop-mode.af-page-group-order .panel,
  html.desktop-mode.af-page-scheduled-order .sec,
  html.desktop-mode.af-page-coming-soon .now-card {
    border-radius: var(--af-r-lg);
    box-shadow: var(--af-shadow-2);
    border: 1px solid var(--af-border);
  }
  html.desktop-mode.af-page-scheduled-order .tgrid,
  html.desktop-mode.af-page-coming-soon .fchip,
  html.desktop-mode.af-page-coming-soon .feat-chips {
    gap: 12px;
  }

  /* group-order.html:19-21 — the Create/Join switch is a SEGMENTED CONTROL, not
     two buttons: gap:0, overflow:hidden, one shared radius, and the active half
     filled solid. Giving it gap:12px (as the rule above did, before .tab-row was
     split out of it) severed the join, so the active half stopped reading as
     "half of one switch" and became an unrelated orange button.

     The stretch is the bigger problem. .tab is flex:1, so the row's width
     becomes the label's width: measured, each tab was 454px at 1024 and 902px at
     1920, all of it holding a 110px label — 257px of empty space on each side of
     the text at 1366. A switch that wide stops being a switch; the label
     disappears into it. Capping the measure is what makes it legible again. */
  html.desktop-mode.af-page-group-order .tab-row {
    gap: 0;
    max-width: 440px;
    margin: 0 auto 24px;
    padding: 4px;
    border-radius: 14px;
  }
  html.desktop-mode.af-page-group-order .tab {
    padding: 12px 18px;
    font-size: 15px;
    border-radius: 10px;
  }
  html.desktop-mode.af-page-group-order .tab:not(.active):hover {
    background: rgba(255, 75, 43, .07);
    color: var(--af-primary);
  }
  /* Keep the label optically centred regardless of which half is longer. */
  html.desktop-mode.af-page-group-order .tab { text-align: center; }

  /* group-order.html:42-43 — the "Order closes in" picker is flex:1 chips in a
     full-width row, the same stretch as .tab was. Measured before this fix: each
     chip 415px wide holding a 40px label, 188px of empty space on either side, at
     a 1262px row. Three options do not need 1262px. Capped to 420px, which is
     ~140px per chip — still a comfortable tap target, and the label is legible. */
  html.desktop-mode.af-page-group-order .timer-row {
    max-width: 420px;
  }
  html.desktop-mode.af-page-group-order .tb {
    padding: 13px 10px;
    font-size: 14px;
  }
  /* "⏰ Order closes in" is a bare inline-styled div (group-order.html:96) with no
     class to hook, so it inherits the row width and sits hard against the
     content edge. Give the block the same measure so the label and the chips it
     labels share one left edge instead of the label floating 200px from them. */
  html.desktop-mode.af-page-group-order #create-form > div[style*="font-weight:700"] {
    max-width: 420px;
  }

  /* ── 24. Wide-screen refinement: only where there is genuinely room ── */
  @media (min-width: 1500px) {
    html.desktop-mode .page { max-width: 1420px; }
    html.desktop-mode #cgrid { grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); }
    html.desktop-mode #mlist,
    html.desktop-mode #olist { grid-template-columns: repeat(auto-fill, minmax(370px, 1fr)); }
    html.desktop-mode.af-page-cart #cart-content { grid-template-columns: minmax(0, 1fr) 412px; }
  }

  /* ── 25. Respect the OS setting ──
     Hover transforms are decorative. With prefers-reduced-motion the user has
     asked for less movement, so they get colour/shadow feedback only. */
  @media (prefers-reduced-motion: reduce) {
    html.desktop-mode *,
    html.phone-frame * {
      transition-duration: .01ms !important;
      animation-duration: .01ms !important;
      animation-iteration-count: 1 !important;
      scroll-behavior: auto !important;
    }
    html.desktop-mode .card:hover,
    html.desktop-mode .feat:hover,
    html.desktop-mode .food-card:hover,
    html.desktop-mode .ocard:hover,
    html.desktop-mode .food-row:hover { transform: none; }
  }

  /* ── 26. Print: a student printing an order receipt should get the phone
     layout, not a sidebar and a 1320px content column. ── */
  @media print {
    html.desktop-mode .af-side,
    html.desktop-mode .af-pubhead,
    html.desktop-mode .af-authside,
    html.desktop-mode .af-viewtoggle,
    html.desktop-mode .bottom-nav { display: none !important; }
    /* af-public pages have no gutter to begin with; af-has-rail pages do. */
    html.desktop-mode body { padding-left: 0; max-width: none; }
    html.desktop-mode .page { max-width: none; padding: 0; }
  }
}

/* ==========================================================================
   DEFAULT HIDES FOR INJECTED NODES — top level, like .af-viewtoggle below.
   Every other layout rule in this file sits inside @media (min-width: 1024px),
   but a "hide this until the desktop layer turns it on" rule has to be the
   DEFAULT, and a default inside the query never fires below the breakpoint.

   Two nodes need one, for two different reasons:

     .af-fgrid     a <div>. Without a hide it is display:block, so in PHONE MODE
                   — where the class is stripped but the node is still in the DOM,
                   because phone mode is a preview at desktop width — it would
                   dump nine unstyled rows into the middle of the phone layout.
     .af-xfeat     reuses the page's own .feat, which sets display:flex in
                   index.html's inline <style>. That inline block loads AFTER
                   this file, so at equal specificity the page would win and the
                   box would stay visible on a phone. :not(.desktop-mode) is what
                   buys the extra specificity without !important.

   Both are belt-and-braces. The structural guarantee is in desktop.js:
   removeInjected() deletes these nodes outright below 1024px, so no width exists
   at which the node is present and unstyled. The audit checks both halves.
   ========================================================================== */
.af-fgrid { display: none; }
html:not(.desktop-mode) .af-xfeat { display: none; }

/* ==========================================================================
   THE TOGGLE
   Fixed bottom-right, above everything. Only exists at desktop width, so it
   cannot appear on a phone — and it is rendered by desktop.js, which only runs
   on desktop widths too.
   ========================================================================== */
/* Horizontal space the toggle occupies at the bottom-right, so a page that owns
     a bottom action bar can reserve exactly that much and the two can never
     overlap. Measured: the toggle renders 214px wide at right:24px. One number in
     one place, because two places guessing at it is how a pay button ends up
     underneath a Desktop/Phone switch.

     Gated with the rest of the layer even though a custom property draws nothing:
     an ungated selector is a rule that can reach a phone, and the audit holds this
     file to that. Only §17.3b reads it, and §17.3b is gated too. */
@media (min-width: 1024px) {
  html { --af-vt-clear: 262px; }   /* 214 wide + 24 inset + 24 breathing room */
}

.af-viewtoggle {
  position: fixed; right: 24px; bottom: 24px; z-index: 10000;
  display: none;
  align-items: center; gap: 3px;
  background: var(--af-card, #fff);
  border: 1px solid var(--af-border, #E5E7EB);
  border-radius: 999px;
  padding: 5px;
  box-shadow: 0 6px 24px rgba(23,32,51,.16);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  user-select: none;
}
@media (min-width: 1024px) { .af-viewtoggle { display: inline-flex; } }

.af-viewtoggle .af-vt-btn {
  display: inline-flex; align-items: center; gap: 7px;
  border: 0; background: transparent; cursor: pointer;
  padding: 8px 15px; border-radius: 999px;
  font-size: 13px; font-weight: 700; color: #64748B;
  transition: background .18s cubic-bezier(.4,0,.2,1), color .18s cubic-bezier(.4,0,.2,1),
              box-shadow .18s cubic-bezier(.4,0,.2,1);
  white-space: nowrap;
}
.af-viewtoggle .af-vt-btn:hover { color: #172033; }
.af-viewtoggle .af-vt-btn[aria-pressed="true"] {
  background: linear-gradient(135deg, #FF4B2B 0%, #FF6A3D 100%);
  color: #fff;
  box-shadow: 0 4px 14px rgba(255,75,43,.34);
}
.af-viewtoggle .af-vt-btn:focus-visible {
  outline: 2px solid #FF4B2B; outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .af-viewtoggle .af-vt-btn { transition: none; }
}
