/*! PolyFishCSS-Content.css | v1.0.0-rc.2-rc.1-rc.1-rc.1-rc.1-rc.1 | polyfish.org | MIT
 *
 * The body of a page: sections, cards, feature and pricing grids, stats,
 * tables, alerts, code blocks, forms, accordions, sidebar navigation,
 * galleries, steps and closing CTA bands. The largest module, and the one
 * most pages need.
 *
 * Depends on: PolyFishCSS-Core.css.
 * Load order: Core -> Headers -> Content -> Footers -> Utilities.
 *
 * CONTENTS
 *   1. Sections
 *   2. Cards
 *   3. Pricing / plan cards
 *   4. Stats
 *   5. Tables
 *   6. Alerts and notes
 *   7. Code
 *   8. Forms
 *   9. Accordion
 *   10. Sidebar navigation
 *   11. Gallery tiles
 *   12. Steps
 *   13. CTA band
 *
 * CONVENTIONS
 *   .pf-block / .pf-block__element / .pf-block--modifier.
 *   Components read role tokens, never palette values. See docs/tokens.
 *
 * NO BEHAVIOUR
 *   Nothing here needs JavaScript. The accordion is a native <details>, the
 *   tables scroll rather than collapse, and the forms are styled controls, not
 *   replacements for them. If a component would need state, it is not in this
 *   file - that is the line the framework holds.
 */

@layer polyfish.core, polyfish.grid, polyfish.headers, polyfish.content, polyfish.forms, polyfish.components, polyfish.footers, polyfish.space, polyfish.effects, polyfish.utilities, polyfish.fonts, polyfish.compat;

/* ==========================================================================
   CASCADE LAYER
   ==========================================================================
   Everything below sits in `polyfish.content`. The layer order is declared in
   every module, so it holds no matter which order you link the files in.

   Why this matters to you: unlayered CSS beats layered CSS regardless of
   specificity. Your own stylesheet overrides any framework rule with a plain
   class selector — no `!important`, no specificity arms race, no worrying
   about whether Utilities loaded last.

     <link rel="stylesheet" href="PolyFishCSS-Core.min.css">
     <link rel="stylesheet" href="my-app.css">   <!-- wins, always -->

   If you want your CSS layered too, name a layer after the framework's:

     @layer polyfish, app;
     @layer app { .card { background: rebeccapurple; } }
   ========================================================================== */

@layer polyfish.content {
  /* ==========================================================================
     #SECTIONS
     ========================================================================== */
  
  /**
   * Section
   *
   * <section class="pf-section pf-section--roomy">
   *   <div class="pf-container">
   *     <div class="pf-section__head">
   *       <p class="pf-eyebrow"><span class="pf-mark"></span> Label</p>
   *       <h2>Heading</h2>
   *       <p class="pf-lede">One line of context.</p>
   *     </div>
   *     ...
   *   </div>
   * </section>
   *
   * Variants: --tight  --roomy  --vast  --alt (deep bg)  --raised (surface bg)
   *
   * Vertical rhythm is a token, not a hardcoded clamp: each variant simply
   * redeclares --pf-section-pad, so a page's whole rhythm can be shifted by
   * setting that property once on a wrapper. Adjacent sections get a hairline
   * rule between them, which is why --alt reads as a band rather than a box.
   */
  
  .pf-section { padding-block: var(--pf-section-pad); }
  .pf-section.pf-section--tight { --pf-section-pad: clamp(2rem, 4vw, 3rem); }
  /* Give a section room to breathe. Use --roomy for a whole page's rhythm and
     --vast for the one or two sections that carry the argument. */
  .pf-section.pf-section--roomy { --pf-section-pad: clamp(4.5rem, 11vw, 9rem); }
  .pf-section.pf-section--vast { --pf-section-pad: clamp(6rem, 16vw, 13rem); }
  .pf-section.pf-section--alt { background: var(--pf-base-900); }
  .pf-section.pf-section--raised { background: var(--pf-surface); }
  .pf-section + .pf-section { border-top: 1px solid var(--pf-border); }
  
  .pf-section__head {
    display: grid;
    gap: var(--pf-space-3);
    margin-bottom: var(--pf-section-head-gap, var(--pf-gap-lg));
    max-width: 62ch;
  }
  .pf-section__head--center { margin-inline: auto; justify-items: center; text-align: center; }
  .pf-section--roomy > * > .pf-section__head,
  .pf-section--vast > * > .pf-section__head { --pf-section-head-gap: var(--pf-space-8); }
  
  /**
   * Eyebrow
   *
   * Sentence case with a small triangle, rather than the tracked-out capitals
   * every SaaS page uses. Caps at 12px are measurably slower to read and the
   * marker does the same job of signalling "label, not heading".
   */
  .pf-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: var(--pf-space-2);
    color: var(--pf-accent);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-sm);
    font-weight: 500;
  }
  
  .pf-lede {
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xl);
    line-height: 1.55;
    max-width: 58ch;
  }
  .pf-muted { color: var(--pf-text-muted); }
  
  /**
   * Prose rhythm.
   *
   * Long-form pages were relying on default paragraph margins, which are
   * tighter than the rest of the framework's spacing and made documentation
   * feel cramped next to the marketing pages. This sets the vertical rhythm
   * from the space scale like everything else.
   */
  .pf-prose > * + * { margin-top: var(--pf-space-5); }
  .pf-prose > h2 { margin-top: var(--pf-space-8); }
  .pf-prose > h3 { margin-top: var(--pf-space-7); }
  .pf-prose > h2 + *,
  .pf-prose > h3 + * { margin-top: var(--pf-space-4); }
  .pf-prose > hr { margin-block: var(--pf-space-8); }
  .pf-prose > .pf-table-wrap,
  .pf-prose > .pf-code,
  .pf-prose > .pf-alert { margin-top: var(--pf-space-6); }
  
  /* ==========================================================================
     #CARDS
     ========================================================================== */
  
  /**
   * Card
   *
   * <article class="pf-card pf-card--facet">
   *   <span class="pf-card__icon">01</span>
   *   <h3 class="pf-card__title">Title</h3>
   *   <p class="pf-card__body">Body copy.</p>
   *   <div class="pf-card__foot"> ... </div>
   * </article>
   *
   * Variants: --facet (clipped corner)  --accent  --flat  --link
   *
   * The card is a flex column so __foot can take margin-top:auto and pin itself
   * to the bottom, which is what keeps a row of cards with uneven copy from
   * ending on ragged buttons.
   *
   * --link turns the whole card into an anchor. Put the <a> on the card itself
   * rather than nesting one inside: nested interactive elements are invalid and
   * make the card a keyboard trap of two tab stops for one destination.
   */
  
  .pf-card {
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-3);
    /* Padding scales with the viewport: 20px on a phone where every pixel of
       line length counts, 32px on a desktop where air is the point. */
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg);
    padding: clamp(1.5rem, 3vw, 2.5rem);
    transition: border-color var(--pf-speed) var(--pf-ease), background-color var(--pf-speed) var(--pf-ease);
  }
  .pf-card__title { font-size: var(--pf-text-xl); line-height: 1.25; }
  .pf-card__body { color: var(--pf-text-muted); line-height: 1.65; }
  .pf-card__foot { margin-top: auto; padding-top: var(--pf-space-4); }
  .pf-card > p { max-width: none; }
  
  .pf-card--facet {
    border-radius: var(--pf-radius);
    clip-path: polygon(0 0, calc(100% - var(--pf-cut)) 0, 100% var(--pf-cut), 100% 100%, 0 100%);
  }
  .pf-card--accent { border-color: var(--pf-border-strong); background: var(--pf-hue-1-wash); }
  .pf-card--flat { background: none; }
  .pf-card--link { text-decoration: none; color: inherit; }
  .pf-card--link:hover { border-color: var(--pf-border-strong); background: var(--pf-surface-raised); color: inherit; }
  
  .pf-card__icon {
    display: grid;
    place-items: center;
    width: 2.6rem;
    height: 2.6rem;
    background: var(--pf-hue-1-wash);
    border: 1px solid rgba(143, 224, 106, 0.3);
    border-radius: var(--pf-radius);
    color: var(--pf-accent);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-sm);
  }
  .pf-card__icon--accent-2 {
    background: var(--pf-hue-2-wash);
    border-color: rgba(229, 177, 137, 0.3);
    color: var(--pf-accent-2);
  }
  
  /* Feature list — compact, icon optional */
  .pf-feature { display: grid; gap: var(--pf-space-2); }
  .pf-feature h3 { font-size: var(--pf-text-lg); }
  .pf-feature p { color: var(--pf-text-muted); font-size: var(--pf-text-base); line-height: 1.6; max-width: 46ch; }
  
  /**
   * Checklist
   *
   * <ul class="pf-checks">
   *   <li>An item</li>
   * </ul>
   *
   * Two-column grid per item so the marker stays put and wrapped lines align to
   * the text, not under the bullet. The marker is a clipped triangle rather
   * than a character, so it never renders as a missing glyph.
   */
  .pf-checks { display: grid; gap: var(--pf-space-2); margin: 0; }
  .pf-checks li {
    display: grid;
    grid-template-columns: 1.1rem 1fr;
    gap: var(--pf-space-3);
    align-items: start;
    color: var(--pf-text-muted);
    font-size: var(--pf-text-base);
    line-height: 1.6;
  }
  .pf-checks li::before {
    content: "";
    width: 0.7rem;
    height: 0.7rem;
    margin-top: 0.45em;
    background: var(--pf-accent);
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  .pf-checks--accent-2 li::before { background: var(--pf-accent-2); }
  .pf-checks--muted li::before { background: var(--pf-text-muted); }
  
  /* ==========================================================================
     #PLAN CARDS
     ========================================================================== */
  
  /**
   * Plan card
   *
   * <article class="pf-plan pf-plan--featured">
   *   <span class="pf-plan__badge">Most picked</span>
   *   <h3 class="pf-plan__name">Team</h3>
   *   <p class="pf-plan__price">$49 <span>per month</span></p>
   *   <ul class="pf-checks"> ... </ul>
   *   <div class="pf-plan__foot"> ... </div>
   * </article>
   *
   * The featured variant is a border and a gradient wash, not a scale
   * transform: growing the middle card breaks the shared baseline and makes the
   * other two look like mistakes.
   */
  
  .pf-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--pf-space-4);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-lg);
    padding: clamp(1.75rem, 3.5vw, 3rem) clamp(1.5rem, 3vw, 2.5rem);
  }
  .pf-plan--featured {
    border-color: var(--pf-accent);
    background: linear-gradient(180deg, var(--pf-hue-1-wash), transparent 55%), var(--pf-surface);
  }
  .pf-plan__name { font-size: var(--pf-text-lg); }
  .pf-plan__note { color: var(--pf-text-muted); font-size: var(--pf-text-sm); }
  .pf-plan__price {
    display: flex;
    align-items: baseline;
    gap: 0.35rem;
    font-family: var(--pf-font-display);
    font-size: var(--pf-text-3xl);
    font-weight: 700;
    letter-spacing: -0.03em;
  }
  .pf-plan__price span { color: var(--pf-text-muted); font-family: var(--pf-font-body); font-size: var(--pf-text-sm); font-weight: 400; }
  .pf-plan__badge {
    position: absolute;
    top: var(--pf-space-4);
    inset-inline-end: var(--pf-space-4);
    background: var(--pf-accent);
    border-radius: var(--pf-radius-pill);
    color: var(--pf-base-950);
    font-size: var(--pf-text-xs);
    font-weight: 600;
    padding: 0.25rem 0.7rem;
  }
  .pf-plan__foot { margin-top: auto; padding-top: var(--pf-space-2); }
  
  /* ==========================================================================
     #STATS
     ========================================================================== */
  
  /**
   * Stat row
   *
   * <ul class="pf-stats">
   *   <li class="pf-stat">
   *     <span class="pf-stat__value">99.98%</span>
   *     <span class="pf-stat__label">Availability</span>
   *   </li>
   * </ul>
   *
   * A rule on the left rather than a box around each figure: four bordered
   * cards in a row read as navigation, four rules read as one set of numbers.
   * Auto-fit means three stats and five stats both look deliberate.
   */
  
  .pf-stats {
    display: grid;
    gap: var(--pf-gap);
    grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
    margin: 0;
  }
  .pf-stat { display: grid; gap: 0.15rem; border-inline-start: 2px solid var(--pf-border-strong); padding-inline-start: var(--pf-space-4); }
  .pf-stat__value {
    font-family: var(--pf-font-display);
    font-size: var(--pf-text-3xl);
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1;
  }
  .pf-stat__label { color: var(--pf-text-muted); font-size: var(--pf-text-sm); }
  
  /* ==========================================================================
     #TABLES
     ========================================================================== */
  
  /**
   * Table
   *
   * <div class="pf-table-wrap">
   *   <table class="pf-table pf-table--zebra">
   *     <thead><tr><th scope="col">Header</th></tr></thead>
   *     <tbody><tr><th scope="row">Row</th><td data-pf="yes">Value</td></tr></tbody>
   *   </table>
   * </div>
   *
   * The wrapper is required: it is what makes a wide table scroll horizontally
   * instead of squeezing columns into unreadable slivers on a phone. min-width
   * on the table is what forces that scroll rather than allowing the squeeze.
   *
   * data-pf="yes" / "no" colours a cell without inventing a class per state,
   * which keeps comparison tables from sprouting a dozen modifiers.
   *
   * Always use scope on header cells. It costs nothing and it is the difference
   * between a screen reader announcing a table and reading a wall of numbers.
   */
  
  .pf-table-wrap {
    overflow-x: auto;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
  }
  .pf-table { font-size: var(--pf-text-base); line-height: 1.55; min-width: 34rem; }
  .pf-table th,
  .pf-table td { padding: 0.85rem 1rem; text-align: start; vertical-align: top; }
  .pf-table thead th {
    background: var(--pf-base-900);
    color: var(--pf-base-50);
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-xs);
    font-weight: 600;
    white-space: nowrap;
  }
  .pf-table tbody tr + tr { border-top: 1px solid var(--pf-border); }
  .pf-table tbody td { color: var(--pf-text-muted); }
  .pf-table tbody th { font-weight: 500; }
  .pf-table--zebra tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.03); }
  
  /* Density, borders and interaction. --hover is for tables whose rows lead
     somewhere; on a static table it promises a click that never happens. */
  .pf-table--compact th,
  .pf-table--compact td { padding: 0.5rem 0.7rem; font-size: var(--pf-text-xs); }
  .pf-table--roomy th,
  .pf-table--roomy td { padding: 1.1rem 1.25rem; }
  .pf-table--bordered th,
  .pf-table--bordered td { border: 1px solid var(--pf-border); }
  .pf-table--hover tbody tr:hover { background: var(--pf-surface-raised); }
  .pf-table--fixed { table-layout: fixed; }
  
  /* Sticky header for long tables. The wrapper needs a max-height for this to
     do anything - without a scroll container there is nothing to stick to. */
  .pf-table-wrap--tall { max-height: 26rem; overflow: auto; }
  .pf-table--sticky thead th {
    position: sticky;
    top: 0;
    z-index: 1;
  }
  /**
   * Stacking table
   *
   * <table class="pf-table pf-table--stack">
   *   <thead><tr><th>Check</th><th>Status</th></tr></thead>
   *   <tbody>
   *     <tr>
   *       <th scope="row" data-pf-label="Check">api-gateway</th>
   *       <td data-pf-label="Status">Healthy</td>
   *     </tr>
   *   </tbody>
   * </table>
   *
   * Below 620px each row becomes a card and each cell shows its column name
   * from data-pf-label. The alternative is horizontal scrolling, which works
   * but makes a six-column table genuinely tedious on a phone.
   *
   * Use it when rows are records to read. Keep the scrolling wrapper when the
   * table is a grid to compare across - stacking destroys column alignment,
   * which is the entire point of a comparison table.
   *
   * The header row is hidden with the same technique as .pf-visually-hidden
   * rather than display:none, so the column names stay in the accessibility
   * tree and the table is still announced as a table.
   */
  @media (max-width: 620px) {
    .pf-table--stack,
    .pf-table--stack tbody,
    .pf-table--stack tr,
    .pf-table--stack td,
    .pf-table--stack th { display: block; }
  
    .pf-table--stack { min-width: 0; }
  
    .pf-table--stack thead {
      position: absolute;
      width: 1px;
      height: 1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
    }
  
    .pf-table--stack tbody tr {
      border: 1px solid var(--pf-border);
      border-radius: var(--pf-radius);
      margin-bottom: var(--pf-space-3);
      padding: var(--pf-space-2) var(--pf-space-4);
    }
    .pf-table--stack tbody tr + tr { border-top: 1px solid var(--pf-border); }
  
    .pf-table--stack tbody th,
    .pf-table--stack tbody td {
      display: flex;
      justify-content: space-between;
      gap: var(--pf-space-4);
      padding-inline: 0;
      text-align: end;
    }
    .pf-table--stack tbody th { text-align: end; }
  
    .pf-table--stack tbody [data-pf-label]::before {
      content: attr(data-pf-label);
      color: var(--pf-text-muted);
      font-size: var(--pf-text-xs);
      font-weight: 500;
      text-align: start;
      padding-inline-end: var(--pf-space-3);
    }
  
    .pf-table--stack tbody td + td,
    .pf-table--stack tbody th + td { border-top: 1px solid var(--pf-border); }
  }
  
  .pf-table caption {
    caption-side: bottom;
    color: var(--pf-text-muted);
    font-size: var(--pf-text-xs);
    padding-top: var(--pf-space-3);
    text-align: start;
  }
  .pf-table td[data-pf="yes"] { color: var(--pf-accent); }
  .pf-table td[data-pf="no"] { color: rgba(169, 188, 216, 0.55); }
  
  /* ==========================================================================
     #ALERTS AND QUOTES
     ========================================================================== */
  
  /**
   * Alert
   *
   * <div class="pf-alert pf-alert--warn">
   *   <p class="pf-alert__title">Careful</p>
   *   <p>What to do about it.</p>
   * </div>
   *
   * Variants: --info  --success  --warn  --danger
   *
   * Colour is carried by a left rule and a wash rather than a filled block, so
   * an alert can sit inside prose without shouting. Nothing here conveys
   * meaning by colour alone - the title does that - which is what keeps the
   * component usable for colour-blind readers.
   */
  
  .pf-alert {
    display: grid;
    gap: var(--pf-space-2);
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-inline-start: 3px solid var(--pf-accent);
    border-radius: var(--pf-radius);
    padding: var(--pf-space-4) var(--pf-space-5);
    font-size: var(--pf-text-base);
  }
  .pf-alert__title { font-family: var(--pf-font-body); font-size: var(--pf-text-base); font-weight: 600; color: var(--pf-text); }
  .pf-alert p { color: var(--pf-text-muted); line-height: 1.65; max-width: none; }
  .pf-alert--info { border-left-color: var(--pf-base-600); }
  .pf-alert--success { border-left-color: var(--pf-hue-1-deep); background: var(--pf-hue-1-wash); }
  .pf-alert--warn { border-left-color: var(--pf-hue-2); background: var(--pf-hue-2-wash); }
  .pf-alert--danger { border-left-color: #e08f8f; background: rgba(224, 143, 143, 0.1); }
  
  .pf-quote {
    border-inline-start: 2px solid var(--pf-accent-2);
    padding-inline-start: var(--pf-space-5);
    font-size: var(--pf-text-lg);
    line-height: 1.5;
  }
  .pf-quote footer { color: var(--pf-text-muted); font-size: var(--pf-text-sm); margin-top: var(--pf-space-3); }
  
  /* ==========================================================================
     #CODE
     ========================================================================== */
  
  /**
   * Code block
   *
   * <div class="pf-code">
   *   <div class="pf-code__bar"><span>file.html</span><span>html</span></div>
   *   <pre><code><span class="pf-tag">&lt;div&gt;</span></code></pre>
   * </div>
   *
   * Highlighting classes (.pf-tag, .pf-attr, .pf-str, .pf-comment) are applied
   * by hand or by whatever highlighter you already run. The framework ships the
   * four colours and no tokeniser, because shipping one would mean shipping
   * JavaScript.
   */
  
  .pf-code {
    background: var(--pf-base-900);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    overflow: hidden;
  }
  .pf-code__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-3);
    background: rgba(255, 255, 255, 0.04);
    border-bottom: 1px solid var(--pf-border);
    color: var(--pf-text-muted);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-xs);
    padding: 0.5rem 0.9rem;
  }
  /**
   * Copy button and sortable header
   *
   * Both elements are created by polyfish.js, not by you. They are styled here
   * so the optional script never has to inject styles - a script that writes
   * CSS is a script that fights your Content-Security-Policy.
   *
   * Without the script neither element exists, and nothing looks unfinished.
   */
  .pf-code__copy {
    background: var(--pf-surface-raised);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-text-muted);
    cursor: pointer;
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-xs);
    padding: 0.2rem 0.6rem;
    min-height: 1.75rem;
  }
  .pf-code__copy:hover { border-color: var(--pf-border-strong); color: var(--pf-text); }
  
  .pf-th-sort {
    display: inline-flex;
    align-items: center;
    gap: 0.4em;
    background: none;
    border: 0;
    color: inherit;
    cursor: pointer;
    font: inherit;
    padding: 0;
  }
  .pf-th-sort::after {
    content: "";
    width: 0.5em;
    height: 0.5em;
    background: currentColor;
    opacity: 0.35;
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
  }
  [aria-sort="ascending"] .pf-th-sort::after { opacity: 1; }
  [aria-sort="descending"] .pf-th-sort::after { opacity: 1; transform: rotate(180deg); }
  
  .pf-code pre {
    margin: 0;
    overflow-x: auto;
    padding: var(--pf-space-4) var(--pf-space-5);
    line-height: 1.7;
    tab-size: 2;
  }
  .pf-code code { color: var(--pf-base-50); font-size: var(--pf-text-sm); }
  .pf-code .pf-tag { color: var(--pf-accent); }
  .pf-code .pf-attr { color: var(--pf-accent-2); }
  .pf-code .pf-str { color: #d9e4ff; }
  .pf-code .pf-comment { color: rgba(169, 188, 216, 0.65); }
  
  /* ==========================================================================
     #FORMS
     ========================================================================== */
  
  /**
   * Field
   *
   * <div class="pf-field">
   *   <label class="pf-label" for="email">Email</label>
   *   <input class="pf-input" id="email" type="email">
   *   <p class="pf-help">Where the receipt goes.</p>
   * </div>
   *
   * Every control needs a real <label for>. Placeholder text is not a label: it
   * disappears on focus, fails contrast in most palettes, and is invisible to
   * anyone using autofill.
   *
   * The select arrow is two linear-gradients rather than a background image, so
   * it needs no asset and recolours with the accent. appearance:none removes
   * the native control, which is why the focus ring is reinstated explicitly
   * below - remove that and keyboard users lose the only focus indicator.
   *
   * Mark invalid fields with aria-invalid="true"; the styling hangs off the
   * attribute so assistive tech and the visual state stay in sync.
   */
  
  .pf-field { display: grid; gap: var(--pf-space-2); }
  .pf-label { font-size: var(--pf-text-base); font-weight: 500; }
  .pf-help { color: var(--pf-text-muted); font-size: var(--pf-text-sm); line-height: 1.5; }
  
  .pf-input,
  .pf-select,
  .pf-textarea {
    width: 100%;
    background: var(--pf-base-900);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    color: var(--pf-text);
    font-size: var(--pf-text-sm);
    padding: 0.75rem 0.9rem;
    transition: border-color var(--pf-speed) var(--pf-ease), box-shadow var(--pf-speed) var(--pf-ease);
  }
  .pf-input::placeholder,
  .pf-textarea::placeholder { color: rgba(169, 188, 216, 0.6); }
  .pf-input:focus,
  .pf-select:focus,
  .pf-textarea:focus {
    border-color: var(--pf-accent);
    box-shadow: var(--pf-ring);
    outline: none;
  }
  .pf-textarea { min-height: 8rem; resize: vertical; }
  .pf-select {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--pf-accent) 50%),
      linear-gradient(135deg, var(--pf-accent) 50%, transparent 50%);
    background-position: right 1.1rem center, right 0.75rem center;
    background-size: 6px 6px, 6px 6px;
    background-repeat: no-repeat;
    padding-inline-end: 2.4rem;
  }
  .pf-input[aria-invalid="true"],
  .pf-textarea[aria-invalid="true"] { border-color: #e08f8f; }
  
  .pf-choice { display: flex; align-items: center; gap: var(--pf-space-3); font-size: var(--pf-text-sm); }
  .pf-choice input { accent-color: var(--pf-hue-1); width: 1.05rem; height: 1.05rem; }
  
  .pf-inline-form {
    display: flex;
    flex-wrap: wrap;
    gap: var(--pf-space-2);
  }
  .pf-inline-form .pf-input { flex: 1 1 14rem; width: auto; }
  
  /* ==========================================================================
     #ACCORDION
     ========================================================================== */
  
  /**
   * Accordion
   *
   * <div class="pf-accordion">
   *   <details open>
   *     <summary>Question</summary>
   *     <p>Answer.</p>
   *   </details>
   * </div>
   *
   * Native <details>, so open state, keyboard handling and find-in-page all
   * work for free, and the content prints expanded. The default marker is
   * removed twice - list-style on summary and the WebKit pseudo-element - which
   * is the pair you need for cross-browser removal.
   */
  
  .pf-accordion { display: grid; gap: var(--pf-space-2); }
  .pf-accordion details {
    background: var(--pf-surface);
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    padding: var(--pf-space-4) var(--pf-space-5);
  }
  .pf-accordion summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-4);
    cursor: pointer;
    font-family: var(--pf-font-display);
    font-size: var(--pf-text-lg);
    font-weight: 600;
    list-style: none;
  }
  .pf-accordion summary::-webkit-details-marker { display: none; }
  .pf-accordion summary::after {
    content: "";
    width: 0.75rem;
    height: 0.75rem;
    flex: none;
    background: var(--pf-accent);
    clip-path: polygon(50% 100%, 0 0, 100% 0);
    transition: transform var(--pf-speed) var(--pf-ease);
  }
  .pf-accordion details[open] summary::after { transform: rotate(180deg); }
  .pf-accordion details[open] summary { margin-bottom: var(--pf-space-3); }
  .pf-accordion p { color: var(--pf-text-muted); font-size: var(--pf-text-base); line-height: 1.65; }
  
  /**
   * Sidebar navigation
   *
   * <aside class="pf-sidenav pf-sidenav--sticky">
   *   <div class="pf-sidenav__group">
   *     <h2 class="pf-sidenav__heading">Section</h2>
   *     <ul class="pf-sidenav__links"> ... </ul>
   *   </div>
   * </aside>
   *
   * Pair it with a two-column .pf-grid. --sticky needs an ancestor that does
   * not clip overflow, which is the usual reason a sticky sidebar silently
   * refuses to stick.
   */
  .pf-sidenav { display: grid; gap: var(--pf-space-5); align-content: start; }
  .pf-sidenav--sticky { position: sticky; top: 6rem; }
  .pf-sidenav__group { display: grid; gap: var(--pf-space-2); }
  .pf-sidenav__heading {
    font-family: var(--pf-font-body);
    font-size: var(--pf-text-sm);
    font-weight: 600;
    color: var(--pf-text);
  }
  .pf-sidenav__links { display: grid; gap: var(--pf-space-2); margin: 0; }
  .pf-sidenav__links a {
    color: var(--pf-text-muted);
    font-size: var(--pf-text-base);
    text-decoration: none;
  }
  .pf-sidenav__links a:hover { color: var(--pf-accent); }
  .pf-sidenav__links a[aria-current] { color: var(--pf-base-50); }
  
  /* ==========================================================================
     #GALLERY
     ========================================================================== */
  
  /**
   * Tile
   *
   * <figure class="pf-tile">
   *   <img src="..." alt="Describe the image, or leave alt empty if decorative">
   *   <figcaption>Caption</figcaption>
   * </figure>
   *
   * aspect-ratio holds the grid steady before images load, which is most of the
   * layout shift on an image-heavy page. object-fit:cover then crops rather
   * than distorting whatever you supply.
   */
  
  .pf-gallery {
    display: grid;
    gap: var(--pf-space-4);
    grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
    margin: 0;
  }
  .pf-tile {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--pf-border);
    border-radius: var(--pf-radius);
    aspect-ratio: 4 / 3;
    background: var(--pf-base-900);
  }
  .pf-tile img { width: 100%; height: 100%; object-fit: cover; }
  .pf-tile figcaption {
    position: absolute;
    inset: auto 0 0;
    background: linear-gradient(transparent, rgba(0, 8, 35, 0.92));
    color: var(--pf-base-50);
    font-size: var(--pf-text-sm);
    padding: var(--pf-space-5) var(--pf-space-4) var(--pf-space-3);
  }
  
  /**
   * Scroller
   *
   * <ul class="pf-scroller">
   *   <li class="pf-scroller__item"> ... </li>
   * </ul>
   *
   * A horizontally scrollable row with snap points, for card rows that would
   * otherwise stack into a very long column on a phone. This is what PolyFish
   * has instead of a carousel: no autoplay, no hidden slides, no script, and
   * the content is reachable by scrolling, keyboard and screen reader alike.
   *
   * scroll-padding matches the gutter so a snapped card is not flush to the
   * edge, and overscroll-behavior-x stops a swipe at the end of the row from
   * triggering the browser's back gesture.
   */
  .pf-scroller {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: min(var(--pf-scroller-item, 20rem), 82%);
    gap: var(--pf-gap);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--pf-gutter);
    padding-bottom: var(--pf-space-3);
    margin: 0;
    /* Bleed to the viewport edge on a phone so the row reads as scrollable,
       while the first card still lines up with the text above it. */
    scrollbar-width: thin;
  }
  .pf-scroller > * { scroll-snap-align: start; }
  .pf-scroller--sm { --pf-scroller-item: 14rem; }
  .pf-scroller--lg { --pf-scroller-item: 26rem; }
  
  @media (min-width: 900px) {
    /* On a wide screen there is room for the row, so stop it scrolling. */
    .pf-scroller--stop {
      grid-auto-flow: row;
      grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
      overflow: visible;
    }
  }
  
  /* ==========================================================================
     #STEPS
     ========================================================================== */
  
  /**
   * Steps
   *
   * <ol class="pf-steps">
   *   <li><h3>Do this first</h3><p>Detail.</p></li>
   * </ol>
   *
   * Numbers come from a CSS counter on an <ol>, so the order is real in the
   * markup and the numbering never drifts from the source. Use this only for
   * genuine sequences; a numbered list of unordered features reads as a ranking
   * nobody intended.
   */
  
  .pf-steps { counter-reset: pf-step; display: grid; gap: var(--pf-space-7); margin: 0; }
  .pf-steps li {
    counter-increment: pf-step;
    display: grid;
    grid-template-columns: 2.2rem 1fr;
    gap: var(--pf-space-4);
    align-items: start;
    max-width: none;
  }
  /**
   * The number is the first grid item, and every real child has to be told to
   * sit in the second column. Without that, a step with a heading AND a
   * paragraph puts the paragraph on the next row in the 2.2rem number column,
   * where it wraps one character per line.
   *
   * Two children looked fine, which is why this survived: the bug only appears
   * once a step has a title and body text, and no amount of CSS parsing or
   * markup validation can see it.
   */
  .pf-steps li::before {
    grid-column: 1;
    grid-row: 1;
    content: counter(pf-step);
    display: grid;
    place-items: center;
    width: 2.2rem;
    height: 2.2rem;
    background: var(--pf-hue-1-wash);
    border: 1px solid var(--pf-border-strong);
    border-radius: var(--pf-radius-sm);
    color: var(--pf-accent);
    font-family: var(--pf-font-mono);
    font-size: var(--pf-text-sm);
  }
  .pf-steps li > * { grid-column: 2; }
  .pf-steps h3 { font-size: var(--pf-text-lg); margin-bottom: 0.25rem; }
  .pf-steps p { color: var(--pf-text-muted); font-size: var(--pf-text-base); line-height: 1.6; }
  
  /**
   * Centred screen
   *
   * <body class="pf-screen">
   *   <main class="pf-container pf-container--narrow"> ... </main>
   * </body>
   *
   * One card, vertically centred on the mesh. For sign-in, error and
   * confirmation pages that have no navigation and no footer.
   */
  .pf-screen {
    display: grid;
    place-items: center;
    min-height: 100vh;
    min-height: 100dvh;
    background-image: var(--pf-mesh);
  }
  .pf-screen__panel { width: min(26rem, 100%); }
  
  /* Surface fill for a gallery tile with no image behind it. */
  .pf-tile__fill { width: 100%; height: 100%; }
  
  /* Type specimen: display-scale text that is not a heading. */
  .pf-specimen {
    font-family: var(--pf-font-display);
    font-size: var(--pf-text-4xl);
    font-weight: 700;
    line-height: var(--pf-leading-tight);
    letter-spacing: -0.03em;
    margin: 0;
  }
  
  /* ==========================================================================
     #CTA BAND
     ========================================================================== */
  
  /**
   * CTA band
   *
   * <div class="pf-cta">
   *   <div class="pf-cta__inner">
   *     <div class="pf-stack pf-gap-3"><h2> ... </h2><p> ... </p></div>
   *     <div class="pf-cluster"> ... buttons ... </div>
   *   </div>
   * </div>
   *
   * The closing argument of a page. Same mesh as the hero, masked from the
   * opposite corner so the two do not read as the same element repeated.
   */
  
  .pf-cta {
    position: relative;
    overflow: hidden;
    background: var(--pf-base-900);
    border: 1px solid var(--pf-border-strong);
    border-radius: var(--pf-radius-lg);
    padding: clamp(2.5rem, 7vw, 5.5rem);
  }
  .pf-cta::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--pf-mesh);
    -webkit-mask-image: linear-gradient(105deg, #000, transparent 62%);
    mask-image: linear-gradient(105deg, #000, transparent 62%);
    pointer-events: none;
  }
  .pf-cta__inner {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--pf-space-5);
  }
  .pf-cta h2 { font-size: var(--pf-text-3xl); max-width: 20ch; }
  .pf-cta p { color: var(--pf-text-muted); max-width: 44ch; }
}
