/* Pudgy Penguins design system — generated bundle. DO NOT EDIT.
   Source: tokens/*.css + ../components.css, concatenated by scripts/build_css_bundle.py.
   Link this one file instead of styles.css so the browser makes a single request:

     <link rel="stylesheet" href="/pudgy/pudgy.css">

   Font URLs resolve to assets/fonts/ next to this file — copy that folder along with it.
   To scope the whole system below your app CSS, import it into a cascade layer instead:

     @import url("/pudgy/pudgy.css") layer(pudgy);
*/

/* ==================== tokens/fonts.css ==================== */
/* Pudgy Penguins webfonts — extracted from brand.pudgypenguins.com guideline document.
   WOFF2 first (~60% smaller, supported everywhere); the source OTF/TTF stays as the fallback
   and as the file to hand to print work. Faces are only downloaded when a page actually uses
   them. Paths are relative to this file — keep tokens/ next to assets/fonts/ when copying. */
@font-face {
  font-family: "FatFrank";
  src:
    url("assets/fonts/FatFrank-Heavy.woff2") format("woff2"),
    url("assets/fonts/FatFrank-Heavy.otf") format("opentype");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Londrina Solid";
  src:
    url("assets/fonts/LondrinaSolid-Black.woff2") format("woff2"),
    url("assets/fonts/LondrinaSolid-Black.ttf") format("truetype");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Londrina Solid";
  src:
    url("assets/fonts/LondrinaSolid-Regular.woff2") format("woff2"),
    url("assets/fonts/LondrinaSolid-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Menco";
  src:
    url("assets/fonts/Menco-Bold.woff2") format("woff2"),
    url("assets/fonts/Menco-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Menco";
  src:
    url("assets/fonts/Menco-Black.woff2") format("woff2"),
    url("assets/fonts/Menco-Black.otf") format("opentype");
  font-weight: 900;
  /* The file's metrics sit the caps 0.085em high, so a button label reads off-centre. These
     lower them to where pudgypenguins.com draws its labels, keeping the line box; the line gap
     is pinned so `line-height: normal` is 1.2 on every platform. */
  ascent-override: 78.5%;
  descent-override: 21.5%;
  line-gap-override: 20%;
  font-style: normal;
  font-display: swap;
}

/* ==================== tokens/colors.css ==================== */
/* Pudgy Penguins color system — exact values from the brand guidelines "Colors" page.
   Ratio (the guideline's color wheel): Crayola Blue ~50% of a layout, the other four primaries
   ~25%, secondaries at most ~25%. The primary palette always makes up at least 75%, and
   backgrounds are always primary. */
:root {
  /* Primary palette — "the Berg": cool blues, soft whites, frosty tones */
  --pp-crayola-blue: #477DF6;  /* THE brand color; cmyk 71/49/0/4 */
  --pp-pengu-blue:   #81ABFF;
  --pp-azure:        #E7F5F9;
  --pp-blizzard:     #F3FBFF;
  --pp-oxford-blue:  #00142D;

  /* Secondary palette — accents only, never lead (max ~25% of a layout) */
  --pp-creamy:     #F9F5E9;  /* cmyk 0/2/6/2 */
  --pp-polly-pink: #FAE7F1;  /* cmyk 0/8/4/2 */
  --pp-blush:      #EE8888;  /* cmyk 0/43/43/7 */
  --pp-jasmine:    #F9DE90;  /* cmyk 0/11/42/2 */
  --pp-mint:       #A7FB97;  /* cmyk 33/0/40/2 */
  --pp-plum:       #FCC7DD;  /* cmyk 0/21/12/1 */

  /* Soft tints, for tonal chips (.pp-chip): each hue lightened toward white just far enough to
     hold a Crayola label at 3:1 or more, which is why Blush and Pengu Blue keep less of their hue.
     The guideline's own product-category art pairs chips this way: one step lighter than their
     hue, under blue type. */
  --pp-plum-soft:    color-mix(in srgb, var(--pp-plum) 40%, #fff);        /* Crayola 3.2:1 */
  --pp-jasmine-soft: color-mix(in srgb, var(--pp-jasmine) 40%, #fff);     /* Crayola 3.3:1 */
  --pp-mint-soft:    color-mix(in srgb, var(--pp-mint) 40%, #fff);        /* Crayola 3.4:1 */
  --pp-blush-soft:   color-mix(in srgb, var(--pp-blush) 20%, #fff);       /* Crayola 3.2:1 */
  --pp-pengu-soft:   color-mix(in srgb, var(--pp-pengu-blue) 25%, #fff);  /* Crayola 3.1:1 */

  /* Semantic aliases */
  --surface-brand:   var(--pp-crayola-blue); /* hero / lead surface */
  --surface-page:    var(--pp-blizzard);     /* default light page */
  --surface-card:    #FFFFFF;
  --surface-input:   #FFFFFF;                /* form fields stay white inside any surface */
  --surface-tint:    var(--pp-azure);
  --surface-dark:    var(--pp-oxford-blue);

  --text-body:       var(--pp-oxford-blue);  /* on light surfaces */
  --text-brand:      var(--pp-crayola-blue); /* headings on light surfaces */
  --text-on-brand:   var(--pp-blizzard);     /* on Crayola Blue */
  --text-on-dark:    var(--pp-blizzard);
  --text-supergraphic: var(--pp-pengu-blue); /* tonal decorative type and sparkles, on Crayola or Azure */

  /* The primary button, as pudgypenguins.com draws it (the source of truth for controls since
     2026-09-28): the site's button blue under a white Menco Black label, 3.7:1, so AA only as
     large text; the 18px default label sits just under that, accepted for the Huddle. On hover the face shifts to #4E7FE3 (a touch darker and greyer) and the label
     drops to 70%, about 2.7:1. */
  --surface-cta:        #477DFD;
  --surface-cta-hover:  #4E7FE3;
  --text-on-cta:        #FFFFFF;
  --text-on-cta-hover:  rgba(255, 255, 255, 0.7);

  /* Anything picked or active that is not a button (the active tab pill, a picked tag or tile):
     Pengu Blue under an Oxford label, 8.1:1, which reads at small sizes. */
  --surface-selected:   var(--pp-pengu-blue);
  --text-on-selected:   var(--pp-oxford-blue);

  /* Fields, as the site draws them: a pale blue pill with button-blue type. */
  --surface-field:       #E1EFF8;
  --surface-field-hover: #E9FAFE;
  --text-field:          #477DFD;
  --border-field-invalid:  #F66A6A;
  --border-field-disabled: #99A1AB;
  --surface-field-disabled: #D9D9D9;

  /* Field placeholders, as the site sets them: Oxford at 40%. */
  --placeholder-color: rgba(0, 20, 45, 0.4);

  --accent:          var(--pp-crayola-blue);
  --accent-soft:     var(--pp-pengu-blue);
  --border-brand:    var(--pp-crayola-blue);

  --link-color:       var(--pp-crayola-blue);
  --link-hover-color: var(--pp-oxford-blue);
}

/* ==================== tokens/typography.css ==================== */
/* Pudgy Penguins type system — from the guideline's Typography page.
   Hierarchy: Fat Frank (primary) > Londrina Solid (secondary) > Menco (tertiary).
   Headlines/subheads are ALWAYS uppercase; body is sentence case.
   Each level steps down at least 50% from the one above.
   Sizes are the guideline's type styles; leading and tracking follow its typesetting rules
   ("Primary Typesetting", "Tracking"), which govern every size. */
:root {
  --font-display: "FatFrank", "Arial Black", sans-serif;        /* headlines, always uppercase */
  --font-subhead: "Londrina Solid", "FatFrank", sans-serif;      /* subheadlines, uppercase, weight 900 */
  --font-body:    "Menco", "Trebuchet MS", sans-serif;           /* body & UI copy, weight 700 */

  /* Leading as a share of the type size: headline 235/188pt and subheadline 90/72pt are 80%,
     body 26/31pt is 120%. */
  --leading-headline: 0.8; /* @kind other */
  --leading-subheadline: 0.8; /* @kind other */
  --leading-body: 1.2; /* @kind other */

  /* Tracking stays at the typeface's standard value (0 in Figma). Kern awkward pairs by hand;
     never track a whole line. */
  --tracking-standard: 0px;

  /* Button labels, one step per button size. Smaller than pudgypenguins.com's 20 / 16 / 14 / 12,
     which read too big in product UI (Zach, 2026-09-28). */
  --button-label-size: 18px;
  --button-label-size-md: 15px;
  --button-label-size-sm: 13px;
  --button-label-size-xs: 11px;

  /* Size tokens are desktop values; the classes below step them down at tablet and mobile.
     The px -line tokens are desktop-only too — pair a responsive size with --leading-* instead. */

  /* Headline — FatFrank 900 */
  --type-headline-size: 150px;
  --type-headline-size-tablet: 130px;
  --type-headline-size-mobile: 84px;
  --type-headline-line: calc(var(--type-headline-size) * var(--leading-headline));
  --type-headline-tracking: var(--tracking-standard);

  /* Headline 2 — FatFrank 900 (smaller hero) */
  --type-headline2-size: 80px;
  --type-headline2-line: calc(var(--type-headline2-size) * var(--leading-headline));
  --type-headline2-tracking: var(--tracking-standard);

  /* Nav — FatFrank 900 (the section index: "01 LOGOS") */
  --type-nav-size: 130px;
  --type-nav-size-mobile: 80px;
  --type-nav-line: calc(var(--type-nav-size) * var(--leading-headline));

  /* Subheadline — Londrina Solid Black */
  --type-subheadline-size: 36px;
  --type-subheadline-line: calc(var(--type-subheadline-size) * var(--leading-subheadline));

  /* Intro copy — Menco Bold */
  --type-intro-size: 40px;
  --type-intro-size-tablet: 32px;
  --type-intro-size-mobile: 24px;
  --type-intro-line: calc(var(--type-intro-size) * var(--leading-body));

  /* Body copy — Menco Bold */
  --type-body-size: 17px;
  --type-body-line: calc(var(--type-body-size) * var(--leading-body));

  /* Small — Menco Bold, uppercase */
  --type-small-size: 15px;
  --type-small-line: calc(var(--type-small-size) * var(--leading-body));

  /* Vertical spacing: the gap between a headline and its subheadline is at least the headline's
     own line gap. At 80% leading Fat Frank's caps sit about 0.11em apart, and the guideline's
     diagram spaces the subheadline roughly twice that; 0.3em (of the headline) clears both. */
  --space-headline-subhead: 0.3em;
}

/* Ready-made classes mirroring the guideline type styles. Line height is a ratio so it follows
   the size down the responsive steps and through any local font-size override. */
.pp-headline    { font-family: var(--font-display); font-weight: 900; font-size: var(--type-headline-size); line-height: var(--leading-headline); letter-spacing: var(--type-headline-tracking); text-transform: uppercase; }
.pp-headline2   { font-family: var(--font-display); font-weight: 900; font-size: var(--type-headline2-size); line-height: var(--leading-headline); letter-spacing: var(--type-headline2-tracking); text-transform: uppercase; }
.pp-nav         { font-family: var(--font-display); font-weight: 900; font-size: var(--type-nav-size); line-height: var(--leading-headline); letter-spacing: var(--tracking-standard); text-transform: uppercase; }
.pp-subheadline { font-family: var(--font-subhead); font-weight: 900; font-size: var(--type-subheadline-size); line-height: var(--leading-subheadline); letter-spacing: var(--tracking-standard); text-transform: uppercase; }
.pp-intro       { font-family: var(--font-body); font-weight: 700; font-size: var(--type-intro-size); line-height: var(--leading-body); letter-spacing: var(--tracking-standard); }
.pp-body        { font-family: var(--font-body); font-weight: 700; font-size: var(--type-body-size); line-height: var(--leading-body); letter-spacing: var(--tracking-standard); }
.pp-small       { font-family: var(--font-body); font-weight: 700; font-size: var(--type-small-size); line-height: var(--leading-body); letter-spacing: var(--tracking-standard); text-transform: uppercase; }

/* Headline → subheadline: never tighter than the headline's own line gap. The margin sits on
   the headline so 0.3em resolves against the headline's size; browsers without :has() get the
   same gap from the subheadline side. */
:is(.pp-headline, .pp-headline2, .pp-nav):has(+ .pp-subheadline) { margin-bottom: var(--space-headline-subhead); }
@supports not selector(:has(*)) {
  :is(.pp-headline, .pp-headline2, .pp-nav) + .pp-subheadline { margin-top: 0.6em; }
}

/* Supergraphic: oversized decorative type in a tonal pair — Pengu Blue on Crayola Blue or on
   Azure. The one place low-contrast type is allowed; never use it for copy people must read. */
.pp-supergraphic {
  font-family: var(--font-display); font-weight: 900; font-size: var(--type-headline-size);
  line-height: var(--leading-headline); letter-spacing: var(--tracking-standard);
  text-transform: uppercase; color: var(--text-supergraphic);
}

/* Responsive steps from the guideline's tablet and mobile contexts. */
@media (max-width: 1023px) {
  .pp-headline, .pp-supergraphic { font-size: var(--type-headline-size-tablet); }
  .pp-intro { font-size: var(--type-intro-size-tablet); }
}
@media (max-width: 639px) {
  .pp-headline, .pp-supergraphic { font-size: var(--type-headline-size-mobile); }
  .pp-nav { font-size: var(--type-nav-size-mobile); }
  .pp-intro { font-size: var(--type-intro-size-mobile); }
}

/* ==================== tokens/shape.css ==================== */
/* Shape, spacing & interaction tokens observed across the guideline document */
:root {
  --radius-card: 32px;      /* color swatches / cards in the guideline use 32px rounding */
  --radius-pill: 999px;     /* buttons & asset callouts are pills */
  --radius-media: 16px;
  --radius-input: 16px;     /* fields are pills (--radius-pill) now; kept for consumers still using it */
  --radius-sm: 8px;         /* checkboxes and other small controls */

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 16px;
  --space-4: 24px;
  --space-5: 32px;
  --space-6: 48px;
  --space-7: 64px;

  --shadow-card: none;      /* the brand is flat — no drop shadows; separation via color blocks */
  --border-w: 2px;          /* outlined elements use a 2px brand-color stroke */
  --overlay-scrim: color-mix(in srgb, var(--pp-oxford-blue) 55%, transparent); /* dialog backdrops */

  --ease-bouncy: cubic-bezier(.34,1.56,.64,1); /* @kind other */
  --dur-quick: 150ms; /* @kind other */
  /* The menus' spring: dropdowns, selects and section navs open on it (a height spring with a
     row stagger, and a small hop on shut), and carousels land their slides on it. Stronger give
     than --ease-bouncy, which stays for small controls. */
  --ease-spring: cubic-bezier(.47,1.64,.41,.8); /* @kind other */

  /* Canonical interactive depth — the sole product-UI shadow exception — as pudgypenguins.com
     draws it: a 2px Oxford frame (the site's 0.27rem border renders at 2px), a small teal lift
     down-right, and an inner shade on the
     bottom-right edge. On hover the lift and shade go flat; nothing moves. */
  --button-ease: cubic-bezier(.445,.05,.55,.95); /* @kind other */
  --button-duration: 200ms; /* @kind other */
  --button-frame-w: 2px;
  --button-frame: inset 0 0 0 var(--button-frame-w) var(--pp-oxford-blue);
  --button-lift: 2.61px 3px 0 rgba(9, 50, 78, 0.23);
  --button-shade: inset calc(-5.209px - var(--button-frame-w)) calc(-5.209px - var(--button-frame-w)) 0 rgba(0, 0, 0, 0.15);
  /* The site draws its shade inside a real 2px border, so the whole 5.209px band shows; under an
     inset-shadow frame the band starts at the face's edge, so it runs the frame's width further. */
  --button-shadow-primary: var(--button-frame), var(--button-shade), var(--button-lift);
  --button-shadow-secondary: var(--button-frame), var(--button-shade), var(--button-lift);
  --button-shadow-dark: var(--button-frame), var(--button-shade), var(--button-lift);
  /* How long an action's outcome shows on its button before the next state (read these from
     script). A failure stays longer: it asks something of the reader. Not motion, so reduced
     motion leaves them alone. */
  --outcome-hold-success: 2500ms; /* @kind other */
  --outcome-hold-error: 5000ms; /* @kind other */

  /* Keyboard focus: a solid 3px Crayola ring, never a foreign accent color. A translucent ring
     vanishes (Crayola at 45% was under 2:1 on the light grounds), so it stays solid. Redefine it
     by ground: Pengu Blue on dark (Oxford) grounds, Oxford on Crayola surfaces. */
  --focus-ring: 3px solid var(--pp-crayola-blue);
  --focus-ring-offset: 3px;

  /* Round icon buttons (arrow / close) — same depth, circular footprint. */
  --icon-button-size: 46px;
  --icon-button-size-lg: 56px;

  /* Form fields, as the site draws them: the button's frame and lift, no inner shade, 59px tall
     like the default button. On focus the frame turns button blue and the lift stays. */
  --input-height: 59px;
  --input-shadow: var(--button-frame), var(--button-lift);
  --input-focus-shadow: inset 0 0 0 var(--button-frame-w) var(--surface-cta), var(--button-lift);
}

/* On a dark (Oxford) ground the Oxford frame and lift vanish, and the face's anti-aliased edge
   is left as a pale hairline that reads as a white outline around every white button and field.
   `.pp-on-dark` on the surface (a footer, a dark band, a dark panel) swaps the frame to Blizzard
   and the lift to Pengu Blue; the face shading inside stays Oxford. The composite tokens are
   declared again here because a custom property resolves its var()s where it is declared, so
   redefining --button-frame alone would not reach them. Scope it to the dark surface itself,
   never to a page: a light panel or a Crayola band inside it keeps the Oxford frame.
   `.pp-card--dark` is such a surface and takes it too. */
.pp-on-dark,
.pp-card--dark {
  --button-frame: inset 0 0 0 var(--button-frame-w) var(--pp-blizzard);
  --button-lift: 2.61px 3px 0 color-mix(in srgb, var(--pp-pengu-blue) 55%, transparent);
  --button-shadow-primary: var(--button-frame), var(--button-shade), var(--button-lift);
  --button-shadow-secondary: var(--button-frame), var(--button-shade), var(--button-lift);
  --button-shadow-dark: var(--button-frame), var(--button-shade), var(--button-lift);
  --input-shadow: var(--button-frame), var(--button-lift);
  --input-focus-shadow: inset 0 0 0 var(--button-frame-w) var(--surface-cta), var(--button-lift);
  --focus-ring: 3px solid var(--pp-pengu-blue);
}

/* Every component animates through these two duration tokens, so zeroing them here is the whole
   reduced-motion story — no `* { transition: none !important }` sledgehammer over app CSS. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-quick: 0.01ms;
    --button-duration: 0.01ms;
  }
}

/* Base defaults, kept at zero specificity so project CSS wins without !important. */
:where(body) {
  margin: 0;
  background: var(--surface-page);
  color: var(--text-body);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: var(--type-body-size);
  line-height: var(--type-body-line);
}
:where(a) { color: var(--link-color); }
:where(a:hover) { color: var(--link-hover-color); }

/* ==================== ../components.css ==================== */
/* Pudgy Penguins components — plain CSS, framework-agnostic.
   Ported from the brand-styled React set; classes are prefixed .pp-.
   All values resolve through tokens/ — never hardcode colors here. */

/* ---------- Button ----------
   As pudgypenguins.com draws them: a pill in the site's button blue under a white Menco Black
   label, framed in 2px Oxford with a small teal lift and an inner shade on the bottom-right
   edge. On hover the face shifts to #4E7FE3 (a touch darker and greyer), the label drops to 70%
   and the depth goes flat; nothing
   moves. Labels are --button-label-size (18px) down to 11px on xs; white on the button blue is 3.7:1, which is AA only for large text (24px, or 18.66px bold). The 18px default sits just under it; Zach accepted that for the Huddle (2026-09-28).
   An icon beside the label (.pp-btn__icon) sits still: no divider, no slide or swap on hover. */
.pp-btn {
  box-sizing: border-box; min-height: 59px;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--font-body); font-weight: 900; text-transform: uppercase;
  letter-spacing: 0.022em; line-height: 1; cursor: pointer;
  border-radius: var(--radius-pill);
  padding: 10px 24px; font-size: var(--button-label-size);
  background: var(--surface-cta); color: var(--text-on-cta);
  border: 0; appearance: none; -webkit-appearance: none;
  background-clip: border-box; touch-action: manipulation;
  box-shadow: var(--button-shadow-primary);
  transition: background-color var(--button-duration) var(--button-ease),
              color var(--button-duration) var(--button-ease),
              box-shadow var(--button-duration) var(--button-ease);
}
.pp-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.pp-btn--lg { min-height: 59px; padding: 10px 24px; font-size: var(--button-label-size); }
.pp-btn--md { min-height: 45px; padding: 8px 20px; font-size: var(--button-label-size-md); }
.pp-btn--sm { min-height: 37px; padding: 6px 20px; font-size: var(--button-label-size-sm); }
.pp-btn--xs {
  min-height: 29px; padding: 4px 20px; font-size: var(--button-label-size-xs);
  background: var(--pp-pengu-blue); color: var(--pp-oxford-blue);
  box-shadow: inset 0 0 0 1.7px var(--pp-oxford-blue), inset -5.477px -5.477px 0 rgba(0, 0, 0, 0.15),
              1.888px 2.175px 0 rgba(9, 50, 78, 0.23);
}
@media (max-width: 767px) { .pp-btn--full-mobile { width: 100%; } }
/* An icon beside the label (Share, Check in, Previous / Next): 0.8em, level with the capitals
   (align-items centres it on them), 10px from the label, and still. No divider between them, and
   no slide, swap or conveyor on hover. */
.pp-btn__icon {
  display: block; flex: none; width: 0.8em; height: 0.8em;
  fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;
}
@media (hover: hover) and (pointer: fine) {
  .pp-btn:not(.pp-btn--secondary, .pp-btn--dark, .pp-btn--on-brand, .pp-btn--xs, .pp-btn--success, .pp-btn--error):not(:disabled):hover {
    background: var(--surface-cta-hover); color: var(--text-on-cta-hover); box-shadow: var(--button-frame);
  }
  .pp-btn--xs:not(:disabled):hover { box-shadow: inset 0 0 0 1.7px var(--pp-oxford-blue); }
}
/* Working: the depth goes flat and the label says what is happening ("Saving", "Disconnecting")
   at full strength. Never `disabled`, which reads as unavailable rather than busy. */
.pp-btn[aria-busy="true"] { background: var(--surface-cta-hover); color: var(--text-on-cta); box-shadow: var(--button-frame); }

.pp-btn--secondary { background: var(--surface-card); color: var(--pp-oxford-blue); box-shadow: var(--button-shadow-secondary); }
/* Dark CTA: the same framed depth on an Oxford face — for dark-surface and third-action CTAs. */
.pp-btn--dark { background: var(--pp-oxford-blue); color: var(--pp-blizzard); box-shadow: var(--button-shadow-dark); }
@media (hover: hover) and (pointer: fine) {
  .pp-btn--secondary:not(:disabled):hover,
  .pp-btn--dark:not(:disabled):hover { box-shadow: var(--button-frame); }
}
.pp-btn--on-brand { background: var(--pp-blizzard); border: var(--border-w) solid var(--pp-blizzard); color: var(--pp-crayola-blue); box-shadow: none; }
.pp-btn--on-brand:hover { background: var(--pp-azure); border-color: var(--pp-azure); color: var(--pp-crayola-blue); }
/* The outcome of what the button just did (Save, Connect, Disconnect, remove): past tense on Mint
   behind a check, or "Couldn't ..." on Blush behind a "!", under an Oxford label (14.8:1, 7.5:1).
   It holds 2.5s on success and 5s on failure (--outcome-hold-success, --outcome-hold-error),
   then the button settles into its next state. While it shows, the button
   takes aria-disabled="true", its handler returns early (Enter and Space still fire a focused
   button) and its accessible name is the outcome; never `disabled`, which drops focus. Announce
   it from a polite status region beside the button: a live region inside a button is not
   announced, its content being presentational. The doubled class outranks aria-busy. */
.pp-btn.pp-btn--success, .pp-btn.pp-btn--error {
  color: var(--pp-oxford-blue); border-color: transparent; cursor: default; pointer-events: none;
}
.pp-btn.pp-btn--success { background: var(--pp-mint); }
.pp-btn.pp-btn--error { background: var(--pp-blush); }

/* ---------- Round icon button (arrow, close, zoom) ----------
   Circular sibling of the button: a white face in the Oxford frame with the same shade and lift,
   the icon in the button blue. On hover the face turns button blue, the icon white, and the depth
   goes flat; nothing moves. --dark flips it to the Oxford face. */
.pp-round-btn {
  box-sizing: border-box; flex: none;
  width: var(--icon-button-size); height: var(--icon-button-size);
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0; border: 0; appearance: none; -webkit-appearance: none;
  border-radius: var(--radius-pill); cursor: pointer;
  background: var(--surface-card); color: var(--surface-cta);
  box-shadow: var(--button-shadow-secondary);
  font-family: var(--font-body); font-weight: 700; line-height: 1;
  touch-action: manipulation;
  transition: background-color var(--button-duration) var(--button-ease),
              color var(--button-duration) var(--button-ease),
              box-shadow var(--button-duration) var(--button-ease);
}
@media (hover: hover) and (pointer: fine) {
  .pp-round-btn:not(:disabled):hover { background: var(--surface-cta); color: var(--text-on-cta); box-shadow: var(--button-frame); }
  .pp-round-btn--dark:not(:disabled):hover { background: var(--pp-oxford-blue); color: var(--pp-blizzard); }
}
.pp-round-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.pp-round-btn--dark {
  background: var(--pp-oxford-blue); color: var(--pp-blizzard);
  box-shadow: var(--button-shadow-dark);
}
.pp-round-btn--lg { width: var(--icon-button-size-lg); height: var(--icon-button-size-lg); }
/* Close-button placement: pinned to the top-right of a dialog, card or media frame. */
.pp-round-btn--overlay { position: absolute; top: var(--space-3); right: var(--space-3); z-index: 2; }
/* The allowed icon substitution: heavy rounded strokes, no glyphs, no icon font. */
.pp-round-btn__icon {
  display: block; width: 22px; height: 22px;
  fill: none; stroke: currentColor; stroke-width: 3;
  stroke-linecap: round; stroke-linejoin: round;
}
.pp-round-btn--lg .pp-round-btn__icon { width: 24px; height: 24px; }

/* ---------- Focus ----------
   One solid ring everywhere (--focus-ring: 3px Crayola), on keyboard focus only. Fields add it
   outside the blue frame their focus already draws. */
.pp-btn:focus-visible,
.pp-round-btn:focus-visible,
.pp-tag:focus-visible,
.pp-callout:focus-visible,
.pp-tabs > button:focus-visible,
.pp-tabs > a:focus-visible,
.pp-checkbox input:focus-visible,
.pp-radio input:focus-visible,
.pp-switch input:focus-visible {
  outline: var(--focus-ring); outline-offset: var(--focus-ring-offset);
}
.pp-input:focus-visible,
.pp-select:focus-visible,
textarea.pp-input:focus-visible,
.pp-input-group:has(:focus-visible) { outline: var(--focus-ring); outline-offset: var(--focus-ring-offset); }
.pp-input-group .pp-input:focus-visible { outline: none; }
/* The ring follows the ground: Pengu Blue on Oxford, Oxford on Crayola, where Crayola vanishes.
   Set the same override on any dark or Crayola section of your own. */
.pp-card--dark  { --focus-ring: 3px solid var(--pp-pengu-blue); }
.pp-card--brand { --focus-ring: 3px solid var(--pp-oxford-blue); }

/* ---------- Card ---------- */
.pp-card {
  background: var(--surface-card); border-radius: var(--radius-card);
  overflow: hidden; display: flex; flex-direction: column;
  box-shadow: var(--shadow-card); /* none — the brand is flat */
}
.pp-card--page  { background: var(--pp-blizzard); }
.pp-card--tint  { background: var(--pp-azure); }
.pp-card--brand { background: var(--pp-crayola-blue); }
.pp-card--dark  { background: var(--pp-oxford-blue); }
.pp-card__media { width: 100%; display: block; object-fit: cover; }
.pp-card__body { padding: 20px 24px; display: flex; flex-direction: column; gap: 8px; }
.pp-card__title {
  font-family: var(--font-subhead); font-weight: 900; text-transform: uppercase;
  font-size: 24px; line-height: 23px; color: var(--pp-crayola-blue);
}
.pp-card__subtitle {
  font-family: var(--font-body); font-weight: 700; font-size: 15px; line-height: 20px;
  text-transform: uppercase; color: var(--pp-oxford-blue);
}
.pp-card__text { font-family: var(--font-body); font-weight: 700; font-size: var(--type-body-size); line-height: var(--type-body-line); color: var(--pp-oxford-blue); }
.pp-card--brand .pp-card__title, .pp-card--dark .pp-card__title,
.pp-card--brand .pp-card__text,  .pp-card--dark .pp-card__text { color: var(--pp-blizzard); }
.pp-card--brand .pp-card__subtitle, .pp-card--dark .pp-card__subtitle { color: var(--pp-pengu-blue); }

/* ---------- Badge ---------- */
.pp-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-body); font-weight: 700; font-size: 12px; line-height: 1;
  text-transform: uppercase;
  padding: 6px 12px; border-radius: var(--radius-pill);
  /* A 12px label needs 4.5:1: Oxford on Crayola is 4.86:1 (Blizzard 3.62:1). */
  background: var(--pp-crayola-blue); color: var(--pp-oxford-blue);
}
.pp-badge--pengu   { background: var(--pp-pengu-blue); color: var(--pp-oxford-blue); }
.pp-badge--mint    { background: var(--pp-mint);       color: var(--pp-oxford-blue); }
.pp-badge--jasmine { background: var(--pp-jasmine);    color: var(--pp-oxford-blue); }
.pp-badge--blush   { background: var(--pp-blush);      color: var(--pp-oxford-blue); } /* Blizzard is 2.47:1 */
.pp-badge--plum    { background: var(--pp-plum);       color: var(--pp-oxford-blue); }
.pp-badge--dark    { background: var(--pp-oxford-blue); color: var(--pp-blizzard); }

/* ---------- Tag (selectable pill) ---------- */
.pp-tag {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-family: var(--font-body); font-weight: 700; font-size: 13px; line-height: 1;
  text-transform: uppercase; padding: 8px 16px; border-radius: var(--radius-pill);
  border: var(--border-w) solid var(--pp-crayola-blue);
  color: var(--pp-crayola-blue); background: transparent;
  transition: background var(--dur-quick), color var(--dur-quick);
}
.pp-tag:hover { background: var(--pp-azure); }
/* Picked: the CTA face, Pengu Blue under Oxford (8.1:1). Crayola put the 13px label at 3.6:1. */
.pp-tag--selected, .pp-tag[aria-pressed="true"] { background: var(--surface-selected); color: var(--text-on-selected); }
.pp-tag--on-dark { border-color: var(--pp-blizzard); color: var(--pp-blizzard); }
.pp-tag--on-dark:hover { background: color-mix(in srgb, var(--pp-blizzard) 15%, transparent); }
.pp-tag--on-dark.pp-tag--selected { background: var(--pp-blizzard); color: var(--pp-crayola-blue); }

/* ---------- Form field ----------
   As pudgypenguins.com draws them: a pale blue pill (--surface-field) with button-blue type,
   the button's Oxford frame and lift but no inner shade, 59px tall. Hover lightens the face and
   drops the lift; focus turns the frame button blue and keeps the lift. The face fills the whole
   pill: nothing shows in its corners. */
.pp-field { display: flex; flex-direction: column; gap: var(--space-2); }
.pp-field > .pp-label {
  font-family: var(--font-body); font-weight: 700; font-size: 15px; line-height: 1.2;
  color: var(--text-body);
}
.pp-input, .pp-select, textarea.pp-input {
  font-family: var(--font-body); font-weight: 700; font-size: 16px; line-height: 20px;
  color: var(--text-field); background: var(--surface-field); background-clip: padding-box;
  min-height: var(--input-height);
  border: 0; border-radius: var(--radius-pill); padding: 8px 16px;
  outline: none; width: 100%; box-sizing: border-box;
  box-shadow: var(--input-shadow);
  transition: background-color var(--button-duration) var(--button-ease),
              box-shadow var(--button-duration) var(--button-ease);
}
textarea.pp-input { border-radius: 10px; resize: vertical; }
.pp-input::placeholder, textarea.pp-input::placeholder { color: var(--placeholder-color); opacity: 1; }
@media (hover: hover) and (pointer: fine) {
  .pp-input:hover, .pp-select:hover, textarea.pp-input:hover { background: var(--surface-field-hover); box-shadow: var(--button-frame); }
}
.pp-input:focus, .pp-select:focus, textarea.pp-input:focus { background: var(--surface-field-hover); box-shadow: var(--input-focus-shadow); }
.pp-input[aria-invalid="true"], .pp-select[aria-invalid="true"] {
  background: var(--surface-field-hover);
  box-shadow: inset 0 0 0 var(--button-frame-w) var(--border-field-invalid), var(--button-lift);
}
.pp-input:disabled, .pp-select:disabled, textarea.pp-input:disabled {
  background: var(--surface-field-disabled); opacity: 0.8; cursor: not-allowed;
  box-shadow: inset 0 0 0 var(--button-frame-w) var(--border-field-disabled);
}
.pp-select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 46px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 18 18' fill='none'%3E%3Cpath d='M4.5 6.75L9 11.25L13.5 6.75' stroke='%23477DFD' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 16px center;
}

/* Search-style field: one pill that holds a leading icon plus a borderless input. An inline
   submit is a medium button inside it, 10px from the right edge. */
.pp-input-group {
  position: relative; display: flex; align-items: center; gap: var(--space-2);
  box-sizing: border-box; width: 100%; min-height: var(--input-height);
  padding: 0 16px; border: 0; border-radius: var(--radius-pill);
  background: var(--surface-field); background-clip: padding-box;
  box-shadow: var(--input-shadow);
  transition: background-color var(--button-duration) var(--button-ease),
              box-shadow var(--button-duration) var(--button-ease);
}
.pp-input-group:focus-within { background: var(--surface-field-hover); box-shadow: var(--input-focus-shadow); }
.pp-input-group .pp-input {
  flex: 1 1 auto; min-width: 0; min-height: 0;
  padding: 0; border-radius: 0; background: transparent; box-shadow: none;
}
.pp-input-group .pp-input:focus, .pp-input-group .pp-input:hover { background: transparent; box-shadow: none; }
.pp-input-group > .pp-btn { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); }
.pp-input-group__icon {
  display: block; flex: none; width: 18px; height: 18px; color: var(--text-field);
  fill: none; stroke: currentColor; stroke-width: 2.5;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ---------- Quantity stepper ----------
   A white pill with - and + at its ends and the number between, drawn with the button's frame,
   shade and lift. Hover flattens it and turns the hovered sign button blue. */
.pp-quantity {
  box-sizing: border-box; display: inline-flex; align-items: center; justify-content: space-between;
  width: 115px; height: 59px; padding-inline: 20px 8px; border-radius: var(--radius-pill);
  background: var(--surface-card); color: var(--pp-oxford-blue);
  box-shadow: var(--button-shadow-secondary);
  font-family: var(--font-body); font-weight: 700; font-size: 16px; line-height: 1;
  transition: box-shadow var(--button-duration) var(--button-ease);
}
.pp-quantity--compact { width: 90px; height: 40px; padding-inline: 12px; }
.pp-quantity__btn {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 24px; height: 24px; padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--pp-oxford-blue); transition: color var(--button-duration) var(--button-ease);
}
.pp-quantity__btn:disabled { opacity: 0.4; cursor: not-allowed; }
.pp-quantity__icon { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; }
.pp-quantity__value { flex: 1 1 auto; text-align: center; }
.pp-quantity:focus-within { box-shadow: inset 0 0 0 var(--button-frame-w) var(--pp-oxford-blue); }
.pp-quantity__btn:focus-visible { outline: var(--focus-ring); outline-offset: 2px; border-radius: 50%; }
@media (hover: hover) and (pointer: fine) {
  .pp-quantity:hover { box-shadow: var(--button-frame); }
  .pp-quantity__btn:not(:disabled):hover { color: var(--surface-cta); }
}

/* ---------- Checkbox ---------- */
.pp-checkbox, .pp-radio, .pp-switch {
  display: inline-flex; align-items: center; gap: 10px; cursor: pointer;
  font-family: var(--font-body); font-weight: 700; font-size: 15px; color: var(--pp-oxford-blue);
}
.pp-checkbox input {
  appearance: none; -webkit-appearance: none; margin: 0; flex: none; cursor: pointer;
  width: 24px; height: 24px; border-radius: var(--radius-sm); box-sizing: border-box;
  border: var(--border-w) solid var(--pp-crayola-blue); background: var(--surface-card);
  transition: background var(--dur-quick);
}
.pp-checkbox input:checked {
  background: var(--pp-crayola-blue) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='11' viewBox='0 0 14 11' fill='none'%3E%3Cpath d='M1.5 5.5L5 9L12.5 1.5' stroke='%23F3FBFF' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center no-repeat;
}

/* ---------- Radio ---------- */
.pp-radio input {
  appearance: none; -webkit-appearance: none; margin: 0; flex: none; cursor: pointer;
  width: 24px; height: 24px; border-radius: 50%; box-sizing: border-box;
  border: var(--border-w) solid var(--pp-crayola-blue); background: var(--surface-card);
  transition: background var(--dur-quick), box-shadow var(--dur-quick);
}
.pp-radio input:checked { background: var(--pp-crayola-blue); box-shadow: inset 0 0 0 4px var(--surface-card); }

/* ---------- Switch ---------- */
.pp-switch input {
  appearance: none; -webkit-appearance: none; margin: 0; flex: none; cursor: pointer;
  width: 48px; height: 28px; border-radius: var(--radius-pill); box-sizing: border-box;
  background: var(--pp-azure); border: var(--border-w) solid var(--pp-pengu-blue);
  position: relative; transition: background var(--dur-quick), border-color var(--dur-quick);
}
.pp-switch input::before {
  content: ""; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px;
  border-radius: 50%; background: var(--surface-card);
  transition: left var(--dur-quick) var(--ease-bouncy);
}
.pp-switch input:checked { background: var(--pp-crayola-blue); border-color: var(--pp-crayola-blue); }
.pp-switch input:checked::before { left: 22px; background: var(--pp-blizzard); }

.pp-checkbox input:disabled, .pp-radio input:disabled, .pp-switch input:disabled { opacity: 0.4; cursor: default; }

/* ---------- Tabs ---------- */
.pp-tabs {
  display: inline-flex; gap: 4px; padding: 4px;
  background: var(--pp-azure); border-radius: var(--radius-pill);
}
.pp-tabs--on-dark { background: color-mix(in srgb, var(--pp-oxford-blue) 25%, transparent); }
.pp-tabs > button, .pp-tabs > a {
  font-family: var(--font-body); font-weight: 700; font-size: 14px; line-height: 1;
  text-transform: uppercase; border: none; cursor: pointer; text-decoration: none;
  padding: 10px 20px; border-radius: var(--radius-pill);
  background: transparent; color: var(--pp-crayola-blue);
  transition: background var(--dur-quick), color var(--dur-quick);
}
.pp-tabs--on-dark > button, .pp-tabs--on-dark > a { color: var(--pp-blizzard); }
/* The active pill is drawn like a primary button: the CTA face under an Oxford label. */
.pp-tabs > [aria-selected="true"], .pp-tabs > .is-active { background: var(--surface-selected); color: var(--text-on-selected); }

/* ---------- File-name callout (pill, guideline style) ---------- */
.pp-callout {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-body); font-weight: 700; font-size: 13px;
  text-transform: uppercase;
  padding: 8px 18px; border-radius: var(--radius-pill);
  background: var(--pp-blizzard); color: var(--pp-crayola-blue);
  border: var(--border-w) solid var(--pp-crayola-blue);
}

/* ---------- Sparkle (decorative motif) ----------
   The guideline's 4-point star, scattered over supergraphic type. Tinted by currentColor, Pengu
   Blue by default; purely decorative, so give it aria-hidden="true". */
.pp-sparkle {
  display: inline-block; flex: none; vertical-align: middle;
  width: 24px; height: 24px; color: var(--text-supergraphic);
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1.5Q13.2 10.8 22.5 12Q13.2 13.2 12 22.5Q10.8 13.2 1.5 12Q10.8 10.8 12 1.5Z' stroke='%23000' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 1.5Q13.2 10.8 22.5 12Q13.2 13.2 12 22.5Q10.8 13.2 1.5 12Q10.8 10.8 12 1.5Z' stroke='%23000' stroke-width='1.5' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
.pp-sparkle--sm { width: 14px; height: 14px; }
.pp-sparkle--lg { width: 40px; height: 40px; }

/* ---------- Number badge ----------
   Oxford circle with a Fat Frank numeral — the guideline's step markers and the NUMBER-BADGE
   callout. Use for ordered steps and counts, not as a status dot. */
.pp-number-badge {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  box-sizing: border-box; width: 48px; height: 48px; border-radius: 50%;
  background: var(--pp-oxford-blue); color: var(--pp-blizzard);
  font-family: var(--font-display); font-weight: 900; font-size: 24px; line-height: 1;
}
.pp-number-badge--brand { background: var(--pp-crayola-blue); }
.pp-number-badge--lg { width: 72px; height: 72px; font-size: 36px; }

/* ---------- Feedback: toast, tooltip, note, status dot ----------
   The tones are palette accents, not a status palette: success Mint, warning Jasmine, error
   Blush, neutral Oxford (or Crayola for brand news). Mint, Jasmine and Blush fail as text on
   light grounds (on white 1.2:1, 1.3:1, 2.5:1), so a message is Oxford on the tone's fill and a
   status mark is the tone inside an Oxford ring, which carries the 3:1 a mark needs. On an
   Oxford ground the tones read as text on their own (Blush 7.5:1, Mint 14.8:1). */
.pp-toast {
  display: inline-flex; align-items: center; gap: var(--space-3);
  padding: 14px 20px; border-radius: var(--radius-pill);
  font-family: var(--font-body); font-weight: 700; font-size: 15px; line-height: 20px;
  background: var(--pp-oxford-blue); color: var(--pp-blizzard);
}
.pp-toast--brand   { background: var(--pp-crayola-blue); color: var(--pp-oxford-blue); }
.pp-toast--success { background: var(--pp-mint);         color: var(--pp-oxford-blue); }
.pp-toast--warning { background: var(--pp-jasmine);      color: var(--pp-oxford-blue); }
.pp-toast--error   { background: var(--pp-blush);        color: var(--pp-oxford-blue); }

/* Tooltip: a flat Oxford bubble 8px off its trigger, shown on hover AND keyboard focus. Put
   .pp-tooltip inside a .pp-tooltip-host and give the bubble role="tooltip" (and the trigger
   aria-describedby). --wrap is for a sentence or two; --below flips it under the trigger;
   --on-dark is a Blizzard bubble for an Oxford ground, where the Oxford one vanishes. */
.pp-tooltip-host { position: relative; display: inline-flex; }
.pp-tooltip {
  position: absolute; z-index: 100; left: 50%; bottom: calc(100% + var(--space-2));
  transform: translate(-50%, 4px); opacity: 0; pointer-events: none;
  white-space: nowrap; padding: var(--space-2) 14px; border-radius: 12px;
  background: var(--pp-oxford-blue); color: var(--pp-blizzard);
  font-family: var(--font-body); font-weight: 700; font-size: 13px; line-height: 18px;
  transition: opacity var(--dur-quick), transform var(--dur-quick) var(--ease-bouncy);
}
.pp-tooltip-host:hover > .pp-tooltip,
.pp-tooltip-host:focus-within > .pp-tooltip { opacity: 1; transform: translate(-50%, 0); }
.pp-tooltip--below { bottom: auto; top: calc(100% + var(--space-2)); }
.pp-tooltip--wrap { white-space: normal; width: max-content; max-width: min(320px, calc(100vw - 24px)); }
.pp-tooltip--on-dark { background: var(--pp-blizzard); color: var(--pp-oxford-blue); }

/* Note: an inline message (a form's submit result, a save error, a confirmation). */
.pp-note {
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-media);
  font-family: var(--font-body); font-weight: 700; font-size: 15px; line-height: 20px;
  background: var(--pp-azure); color: var(--pp-oxford-blue);
}
.pp-note--success { background: var(--pp-mint); }
.pp-note--warning { background: var(--pp-jasmine); }
.pp-note--error   { background: var(--pp-blush); }

/* Status dot: linked, live, failed, off. Put it before Oxford text ("Failed to connect"), never
   let the colour carry the meaning alone. A destructive menu row is Oxford text with an --error
   dot, never an off-palette red. */
.pp-status-dot {
  display: inline-block; flex: none; width: 8px; height: 8px; border-radius: 50%;
  background: var(--pp-oxford-blue); box-shadow: inset 0 0 0 1.5px var(--pp-oxford-blue);
}
.pp-status-dot--success { background: var(--pp-mint); }
.pp-status-dot--warning { background: var(--pp-jasmine); }
.pp-status-dot--error   { background: var(--pp-blush); }
.pp-status-dot--off     { background: transparent; }

/* ---------- Chip (tonal) ----------
   A chip names a thing: a category, a type, an interest. It is the soft tint of its hue under a
   Crayola label, the guideline's tonal pairing (a step lighter than its hue, blue type on it).
   Badges (.pp-badge) mark status or emphasis and stay saturated under Oxford. Crayola on the soft
   tints is 3.1-3.6:1, so chips carry short labels only, bold at 14px, never a sentence. */
.pp-chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-1) 12px; border: 0; border-radius: var(--radius-pill);
  font-family: var(--font-body); font-weight: 700; font-size: 14px; line-height: 18px;
  white-space: nowrap;
  background: var(--pp-azure); color: var(--pp-crayola-blue);
}
.pp-chip--plum    { background: var(--pp-plum-soft); }
.pp-chip--jasmine { background: var(--pp-jasmine-soft); }
.pp-chip--mint    { background: var(--pp-mint-soft); }
.pp-chip--blush   { background: var(--pp-blush-soft); }
.pp-chip--pengu   { background: var(--pp-pengu-soft); }
/* On a blue ground the tonal step runs the other way: a deeper blue chip under a white label. */
.pp-chip--on-blue { background: var(--pp-crayola-blue); color: #fff; }

/* ---------- Scroller and scroll hints ----------
   A sideways row that says it runs on. Put .pp-scroller on the element that scrolls, inside the
   element that draws and clips the round track (position: relative; overflow: hidden), never on
   the track itself: the mask fades everything the element paints. Script sets data-fade-start /
   data-fade-end on the scroller while its first / last item is not fully in view (an
   IntersectionObserver rooted on the scroller at a 0.98 threshold). At each end with more past it
   a .pp-scroll-hint, the scroller's sibling, shows a bare chevron in the track's rounded end, in
   the track's label colour, with no face, frame or lift. The row stays clear under it (the outer
   40px) and fades in beyond it (64px). The hit area is the end's full height and 40px wide; a tap
   scrolls 80% of the row. Hints are a pointer shortcut: aria-hidden, tabindex="-1", and a
   mousedown that does not take focus. The React twin is ScrollHints. */
@property --pp-fade-start { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --pp-fade-end   { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --pp-clear-start { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --pp-clear-end   { syntax: "<length>"; inherits: false; initial-value: 0px; }
.pp-scroller {
  overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none;
  --pp-fade-start: 0px; --pp-fade-end: 0px; --pp-clear-start: 0px; --pp-clear-end: 0px;
  -webkit-mask-image: linear-gradient(to right, transparent var(--pp-clear-start), #000 var(--pp-fade-start), #000 calc(100% - var(--pp-fade-end)), transparent calc(100% - var(--pp-clear-end)));
          mask-image: linear-gradient(to right, transparent var(--pp-clear-start), #000 var(--pp-fade-start), #000 calc(100% - var(--pp-fade-end)), transparent calc(100% - var(--pp-clear-end)));
  transition: --pp-fade-start var(--dur-quick) ease-out, --pp-fade-end var(--dur-quick) ease-out,
              --pp-clear-start var(--dur-quick) ease-out, --pp-clear-end var(--dur-quick) ease-out;
}
.pp-scroller::-webkit-scrollbar { display: none; }
.pp-scroller[data-fade-start] { --pp-fade-start: 64px; --pp-clear-start: 40px; }
.pp-scroller[data-fade-end]   { --pp-fade-end: 64px; --pp-clear-end: 40px; }
.pp-scroll-hint {
  position: absolute; top: 0; bottom: 0; z-index: 2; box-sizing: border-box; width: 40px;
  margin: 0; padding: 0; border: 0; background: none; appearance: none; -webkit-appearance: none;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  color: var(--pp-oxford-blue);
  opacity: 0; pointer-events: none; transition: opacity var(--dur-quick);
}
/* Inset so the chevron is centred in the track's rounded end: half the track's padding-box height
   less 20px (4px in a 48px track). */
.pp-scroll-hint--start { left: var(--pp-scroll-hint-inset, 4px); }
.pp-scroll-hint--end   { right: var(--pp-scroll-hint-inset, 4px); }
.pp-scroller[data-fade-start] ~ .pp-scroll-hint--start,
.pp-scroller[data-fade-end] ~ .pp-scroll-hint--end { opacity: 1; pointer-events: auto; }
/* On a dark (Oxford) track: the chevron in the track's Pengu Blue labels. */
.pp-scroll-hint--on-dark { color: var(--pp-pengu-blue); }
.pp-scroll-hint__icon {
  display: block; width: 18px; height: 18px;
  fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;
  transition: transform var(--button-duration) var(--button-ease);
}
.pp-scroll-hint--start .pp-scroll-hint__icon { transform: rotate(180deg); }
.pp-scroll-hint:active .pp-scroll-hint__icon { transform: scale(0.85); }
.pp-scroll-hint--start:active .pp-scroll-hint__icon { transform: rotate(180deg) scale(0.85); }

/* ---------- Back link ----------
   Back to the parent page, in the top-left corner of the page's content card, never in the
   heading band. The small secondary pill with a chevron and its label; below 768px (or with
   --round wherever the label would crowd the content) the chevron alone in the 46px round button,
   the label kept for screen readers. The React twin is BackLink. */
.pp-back-link {
  display: inline-flex; align-items: center; gap: var(--space-2); box-sizing: border-box;
  min-height: 44px; padding: 0 var(--space-3) 0 var(--space-2); border-radius: var(--radius-pill);
  background: var(--surface-card); color: var(--pp-oxford-blue); text-decoration: none;
  box-shadow: var(--button-shadow-secondary);
  font-family: var(--font-body); font-weight: 700; font-size: 14px; line-height: 1; text-transform: uppercase;
  transition: transform var(--button-duration) var(--button-ease), box-shadow var(--button-duration) var(--button-ease);
}
@media (hover: hover) and (pointer: fine) { .pp-back-link:hover { box-shadow: var(--button-frame); color: var(--pp-oxford-blue); } }
.pp-back-link__icon {
  display: block; flex: none; width: 18px; height: 18px;
  fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;
}
.pp-back-link--round { justify-content: center; width: var(--icon-button-size); min-height: var(--icon-button-size); padding: 0; }
.pp-back-link--round .pp-back-link__label {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
@media (max-width: 767px) {
  .pp-back-link { justify-content: center; width: var(--icon-button-size); min-height: var(--icon-button-size); padding: 0; }
  .pp-back-link__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* ---------- Sticker badges ----------
   The site's sticker badges, beside .pp-badge (which stays): NEW (Mint starburst), LIMITED
   EDITION (peach seal with sparkles) and POPULAR! (Jasmine pill with a sparkle). Each is an
   outlined SVG in assets/badges/ with its own hard drop shadow; place them as <img> so each keeps
   its own filter. Stack them top-left over a product image. */
.pp-sticker { display: block; height: auto; pointer-events: none; user-select: none; }
.pp-sticker--new { width: 74px; }
.pp-sticker--limited { width: 74px; }
.pp-sticker--popular { width: 134px; }
@media (max-width: 767px) {
  .pp-sticker--new, .pp-sticker--limited { width: 44px; }
  .pp-sticker--popular { width: 94px; }
}
.pp-sticker-stack {
  position: absolute; top: var(--space-2); left: var(--space-2); z-index: 1;
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1);
}

/* ---------- Hover style ----------
   Hover never moves or recolours content. A card's media zooms a touch inside its frame; nav and
   footer links get a hand-drawn loop with three sparkle ticks; card titles get a hand-drawn
   underline revealed left to right. All for fine pointers, and still under reduced motion. */
.pp-media-zoom { overflow: hidden; }
.pp-media-zoom img, .pp-media-zoom video { transition: scale 0.2s cubic-bezier(.445,.05,.55,.95); }
@media (hover: hover) and (pointer: fine) {
  .pp-media-zoom:hover img, .pp-media-zoom:hover video,
  :hover > .pp-media-zoom img, :hover > .pp-media-zoom video { scale: 1.03; }
}

/* The loop: an SVG path (assets/hover/drawn-circle.html) drawn by stroke-dashoffset, 0.45s in,
   0.3s out, plus three sparkle ticks top-right at 120/165/210ms. --on-dark draws it white. */
.pp-link-loop { position: relative; display: inline-block; color: inherit; text-decoration: none; }
.pp-link-loop__circle {
  position: absolute; left: -3px; top: 50%; width: calc(100% + 6px); height: 190%;
  translate: 0 -50%; overflow: visible; pointer-events: none;
}
.pp-link-loop__sparkle {
  position: absolute; right: -14px; top: -12px; width: 16px; height: 16px;
  overflow: visible; pointer-events: none;
}
.pp-link-loop__circle path, .pp-link-loop__sparkle path {
  fill: none; stroke: var(--surface-cta); stroke-width: 2px; stroke-linecap: round;
  stroke-dasharray: 100; stroke-dashoffset: 100;
  transition: stroke-dashoffset 0.3s cubic-bezier(.445,.05,.55,.95);
}
.pp-link-loop--on-dark .pp-link-loop__circle path,
.pp-link-loop--on-dark .pp-link-loop__sparkle path { stroke: #FFFFFF; }
.pp-link-loop--on-dark .pp-link-loop__circle { left: -15%; width: 130%; }
@media (hover: hover) and (pointer: fine) {
  .pp-link-loop:hover .pp-link-loop__circle path { stroke-dashoffset: 0; transition-duration: 0.45s; }
  .pp-link-loop:hover .pp-link-loop__sparkle path { stroke-dashoffset: 0; transition-duration: 0.3s; }
  .pp-link-loop:hover .pp-link-loop__sparkle path:nth-child(1) { transition-delay: 120ms; }
  .pp-link-loop:hover .pp-link-loop__sparkle path:nth-child(2) { transition-delay: 165ms; }
  .pp-link-loop:hover .pp-link-loop__sparkle path:nth-child(3) { transition-delay: 210ms; }
}

/* The underline: assets/hover/drawn-underline.svg stretched under the title, revealed by
   clip-path over 0.6s. Put the SVG (class __line) inside the title; the card is the hover target. */
.pp-underline-reveal { position: relative; display: inline-block; }
.pp-underline-reveal__line {
  position: absolute; left: 0; right: 0; top: calc(100% + 1px); width: 100%; height: 5.6px;
  clip-path: inset(0 100% 0 0); pointer-events: none;
  transition: clip-path 0.6s cubic-bezier(.22,1,.36,1);
}
.pp-underline-reveal__line path { fill: var(--surface-cta); stroke: var(--surface-cta); }
@media (hover: hover) and (pointer: fine) {
  .pp-underline-reveal:hover .pp-underline-reveal__line,
  :hover > .pp-underline-reveal .pp-underline-reveal__line,
  :hover > * > .pp-underline-reveal .pp-underline-reveal__line { clip-path: inset(0); }
}

/* ---------- Footer locale pill ----------
   The language and currency selector on the Crayola footer: a small outline pill, Menco Black
   14px uppercase in white, with a flag and a caret. */
.pp-locale-pill {
  display: inline-flex; align-items: center; gap: var(--space-2); box-sizing: border-box;
  min-height: 37px; padding: 6px 11px; border: 2px solid rgba(255, 255, 255, 0.3); border-radius: 42px;
  background: transparent; color: #FFFFFF; cursor: pointer;
  font-family: var(--font-body); font-weight: 900; font-size: 14px; line-height: 1; text-transform: uppercase;
}
