/* Theme-independent layout for roastier.af.codes.
   Color tokens and the glow and steam painted with them live in
   index-light.css / index-dark.css. */

:root {
    --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --spring: cubic-bezier(0.34, 1.56, 0.64, 1);

    /* Scroll-to-top button geometry. The footer derives its bottom padding from
       these, so the button and the footer text can never collide. */
    --fab-size: 2.5rem;
    --fab-inset: 1.5rem;
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
}

body {
    margin: 0;
    font-family: var(--font);
    line-height: 1.5;
    background: var(--bg);
    color: var(--fg);
    -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
p {
    margin: 0;
}

img {
    display: block;
    max-width: 100%;
    height: auto;
}

/* Every themed image is a <picture> so it can carry a dark variant. Left
   inline it would put the block-level image in an inline box, adding a
   line-height gap under it. */
picture {
    display: block;
}

a {
    color: inherit;
}

code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .9em;
}

a:focus-visible,
button:focus-visible {
    outline: 2px solid var(--accent-text);
    outline-offset: 2px;
}

.container {
    max-width: 68rem;
    margin: 0 auto;
    padding: 0 1.25rem;
}

/* Hero ------------------------------------------------------------------- */

.section-hero {
    /* .hero-sky, .top-brand and .top-actions are absolute; without this they
       would anchor to the initial containing block instead of the hero. The
       glow is wider than narrow viewports, so it's clipped here rather than
       scrolling the page sideways. */
    position: relative;
    overflow: hidden;
    overflow: clip;
    padding: 6rem 0 5rem;
    text-align: center;
}

/* The theme sheets paint the glow and color the steam. Both fade out before
   the hero's bottom edge, where the clip would otherwise cut them off in a
   line. */
.hero-sky {
    position: absolute;
    inset: 0;
    pointer-events: none;
    -webkit-mask-image: linear-gradient(to bottom, #000 60%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 60%, transparent 100%);
}

/* Steam rising up the hero's sides, drawn like the wisps over the icon's cup.
   It fades out going up, so it thins before it reaches the title. */
.steam {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    color: var(--steam);
    -webkit-mask-image: linear-gradient(to top, #000 25%, transparent 80%);
    mask-image: linear-gradient(to top, #000 25%, transparent 80%);
}

.steam path {
    fill: none;
    stroke: currentColor;
    stroke-width: 26;
    stroke-linecap: round;
    animation: steam-drift 9s ease-in-out infinite alternate;
}

.steam path:nth-child(2) {
    animation-delay: -3s;
}

.steam path:nth-child(3) {
    animation-delay: -6s;
}

@keyframes steam-drift {
    from {
        transform: translate(-10px, 12px);
    }

    to {
        transform: translate(10px, -12px);
    }
}

.hero-copy,
.hero-media,
.top-brand,
.top-actions {
    position: relative;
    z-index: 1;
}

/* Top brand and actions -------------------------------------------------- */

.top-brand,
.top-actions {
    position: absolute;
    top: 1rem;
    height: 2.5rem;
    display: flex;
    align-items: center;
}

.top-brand {
    left: 1.5rem;
}

.top-actions {
    right: 1.5rem;
    gap: .5rem;
}

.top-brand .brand-logo {
    display: inline-flex;
    /* The padding keeps the monogram's far corners inside the circle. */
    padding: .25rem;
    background: var(--logo-circle);
    box-shadow: 0 2px 6px var(--icon-shadow);
    border-radius: 50%;
}

.top-brand .brand-logo img {
    width: 2rem;
}

.top-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: none;
    color: inherit;
    cursor: pointer;
    opacity: .75;
    transition: opacity .2s ease, color .2s ease;
}

@media (hover: hover) and (pointer: fine) {
    .top-btn:hover {
        opacity: 1;
        color: var(--accent-text);
    }
}

.top-btn:focus-visible {
    opacity: 1;
}

.theme-toggle .icon-sun,
.theme-toggle .icon-moon {
    display: none;
}

/* App icon and title ----------------------------------------------------- */

/* Rendered from AppIcon.icon with Icon Composer's ictool, so the plate and
   corner mask are already in the image; drop-shadow follows its alpha. */
.app-icon {
    width: 7rem;
    margin: 0 auto;
}

.app-icon img {
    width: 100%;
    filter: drop-shadow(0 .6rem 1.2rem var(--icon-shadow));
}

.hero-copy h1 {
    display: inline-block;
    margin-top: 1.5rem;
    font-size: clamp(2.75rem, 7vw, 4.25rem);
    font-weight: 700;
    letter-spacing: -.035em;
    line-height: 1.1;
    color: var(--fg);
}

/* The name is painted in the icon's coffee wherever text can be a gradient's
   clip; elsewhere it stays plain --fg. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
    .hero-copy h1 {
        background: var(--title-gradient);
        -webkit-background-clip: text;
        background-clip: text;
        -webkit-text-fill-color: transparent;
    }
}

.tagline {
    max-width: 36rem;
    margin: 1rem auto 0;
    font-size: clamp(1.05rem, 1.6vw, 1.2rem);
    line-height: 1.55;
    color: var(--secondary);
    text-wrap: balance;
}

/* Buttons ---------------------------------------------------------------- */

.cta-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .75rem;
    margin-top: 2rem;
}

.btn-primary,
.btn-ghost {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    height: 3rem;
    padding: 0 1.3rem;
    border-radius: .55rem;
    font-size: .95rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: transform .3s var(--spring);
}

/* Filled with AccentColor, the icon's coffee. */
.btn-primary {
    background: var(--accent);
    color: var(--on-accent);
    box-shadow: 0 .5rem 1.25rem -.5rem var(--accent);
}

/* Glass, over the glow. */
.btn-ghost {
    border: 1px solid var(--glass-border);
    background: var(--glass);
    -webkit-backdrop-filter: blur(12px) saturate(160%);
    backdrop-filter: blur(12px) saturate(160%);
    color: var(--fg);
}

/* Two-line labels, shorter together than the button, so both buttons stay
   the same height. */
.btn-stack {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.15;
}

/* Full opacity: white faded on the light theme's coffee drops below 4.5:1. */
.btn-subtext {
    font-size: .7rem;
    font-weight: 500;
}

.btn-ghost .btn-subtext {
    color: var(--secondary);
}

@media (hover: hover) and (pointer: fine) {
    .btn-primary:hover,
    .btn-ghost:hover {
        transform: scale(1.03);
    }
}

/* Popover screenshots ---------------------------------------------------- */

/* Captures of the menu bar popover, cut out along its own alpha, so they
   carry its arrow and rounded corners and draw no frame; drop-shadow follows
   the alpha. 22rem keeps the 652px-wide captures under 2x. Every capture
   shares one size, which the aspect-ratio and each <img>'s width and height
   repeat (AGENTS.md has the recipe). */
.popover-shot {
    width: 100%;
    max-width: 22rem;
    margin: 0 auto;
    aspect-ratio: 652 / 558;
    filter: drop-shadow(0 1px 2px var(--popover-rim-shadow)) drop-shadow(0 1.25rem 2rem var(--media-shadow));
}

.hero-media {
    margin-top: 4rem;
}

/* Features --------------------------------------------------------------- */

.section-feature {
    padding: 5rem 0;
}

.feature-split {
    max-width: 60rem;
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: 4rem;
}

.feature-split-reverse .feature-text {
    order: 2;
}

.feature-text {
    max-width: 28rem;
    justify-self: center;
}

.section-centered {
    text-align: center;
}

.section-centered .feature-copy {
    max-width: 36rem;
    margin-left: auto;
    margin-right: auto;
}

.section-feature h2 {
    margin-top: 1rem;
    font-size: clamp(1.9rem, 3.5vw, 2.6rem);
    font-weight: 700;
    letter-spacing: -.03em;
    line-height: 1.1;
}

.feature-copy {
    margin-top: 1rem;
    font-size: 1.1rem;
    line-height: 1.6;
    color: var(--secondary);
    text-wrap: pretty;
}

/* Section labels are capsules filled with the icon's coffee, matching the
   download button. */
.chip {
    display: inline-flex;
    padding: .3rem .85rem;
    border-radius: 999px;
    background: var(--chip-bg);
    color: var(--chip-fg);
    font-size: .875rem;
    font-weight: 600;
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, .2),
        inset 0 1px 0 rgba(255, 255, 255, .3),
        0 1px 2px rgba(0, 0, 0, .1),
        0 .35rem .9rem -.35rem var(--chip-bg);
}

/* Details ---------------------------------------------------------------- */

/* Plain columns between hairlines rather than cards: a glass surface reads as
   clickable, and none of these are links. Keep the descriptions about the
   same length so the columns wrap to the same height. */
.details {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    max-width: 56rem;
    margin: 0 auto;
}

.detail {
    padding: .25rem 1.5rem;
    text-align: center;
}

.detail + .detail {
    border-left: 1px solid var(--hairline);
}

/* Undoes .section-feature h2, which this shares a specificity with. */
.detail h2 {
    margin-top: 0;
    font-size: 1.05rem;
    letter-spacing: normal;
    line-height: 1.5;
    color: var(--accent-text);
}

.detail p {
    margin-top: .35rem;
    font-size: .95rem;
    color: var(--secondary);
    text-wrap: pretty;
}

/* Assertions table ------------------------------------------------------- */

.assertions {
    width: 100%;
    max-width: 44rem;
    margin: 2.5rem auto 0;
    border: 1px solid var(--hairline);
    border-radius: 1rem;
    /* Collapsed borders ignore border-radius, so the table is separate with
       zero spacing and each cell draws only its top rule. */
    border-collapse: separate;
    border-spacing: 0;
    overflow: hidden;
    background: var(--surface);
    text-align: left;
}

.assertions th,
.assertions td {
    padding: .8rem 1.1rem;
    vertical-align: top;
}

.assertions tbody td {
    border-top: 1px solid var(--hairline);
}

.assertions th {
    font-size: .85rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--secondary);
}

.assertions td:first-child code {
    color: var(--accent-text);
    font-weight: 600;
}

/* Long assertion names break rather than widen the table on phones. */
.assertions td:nth-child(2) code {
    overflow-wrap: anywhere;
}

.assertions td:last-child {
    color: var(--secondary);
}

/* Footer ----------------------------------------------------------------- */

.site-footer {
    /* The scroll-to-top button is fixed over the bottom-right corner, and at
       narrow widths this text is wide enough to run under it once the page is
       scrolled to the end. Reserve the button's band plus a gap. */
    padding: 4rem 1.25rem calc(var(--fab-inset) + var(--fab-size) + 1rem);
    text-align: center;
    font-size: .875rem;
    color: var(--secondary);
}

.site-footer a {
    text-decoration: none;
}

@media (hover: hover) and (pointer: fine) {
    .site-footer a:hover {
        color: var(--accent-text);
        text-decoration: underline;
    }
}

/* Scroll-to-top ---------------------------------------------------------- */

/* Do NOT rename this to a generic "back to top" name (jump-to-top, back-to-top,
   scroll-to-top): ad-block cosmetic filters hide those id/class names, which
   makes the button vanish in browsers with a content blocker. Glass, like the
   ghost button. */
.overview-return {
    position: fixed;
    right: var(--fab-inset);
    bottom: var(--fab-inset);
    z-index: 300;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--fab-size);
    height: var(--fab-size);
    padding: 0;
    border: 1px solid var(--glass-border);
    border-radius: 50%;
    background: var(--glass);
    -webkit-backdrop-filter: blur(12px) saturate(160%);
    backdrop-filter: blur(12px) saturate(160%);
    color: var(--fg);
    box-shadow: 0 4px 16px var(--glass-shadow);
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transform: translateY(.5rem);
    transition: opacity .25s ease, transform .3s var(--spring), visibility .25s ease;
}

.overview-return.visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

@media (hover: hover) and (pointer: fine) {
    .overview-return.visible:hover {
        transform: translateY(0) scale(1.05);
    }
}

/* Responsive ------------------------------------------------------------- */

@media (max-width: 820px) {
    .section-feature {
        padding: 4rem 0;
    }

    .feature-split {
        grid-template-columns: 1fr;
        gap: 2.5rem;
        text-align: center;
    }

    .feature-split-reverse .feature-text {
        order: 0;
    }

    .feature-text {
        max-width: 34rem;
    }
}

/* In em, so the columns also stack when enlarged text would squeeze them. */
@media (max-width: 45em) {
    .details {
        grid-template-columns: 1fr;
        max-width: 28rem;
    }

    .detail {
        padding: 1.25rem 0;
    }

    .detail + .detail {
        border-left: none;
        border-top: 1px solid var(--hairline);
    }

    /* One card per row, each cell labeled from its data-label. */
    .assertions thead {
        display: none;
    }

    .assertions,
    .assertions tbody,
    .assertions tr,
    .assertions td {
        display: block;
    }

    .assertions tbody tr + tr {
        border-top: 1px solid var(--hairline);
    }

    .assertions tbody td {
        border-top: none;
        padding: .2rem 1.1rem;
    }

    .assertions tbody td:first-child {
        padding-top: .9rem;
    }

    .assertions tbody td:last-child {
        padding-bottom: .9rem;
    }

    .assertions td:not(:first-child)::before {
        content: attr(data-label) ": ";
        font-weight: 600;
        color: var(--secondary);
    }
}

@media (max-width: 600px) {
    .section-hero {
        padding: 5rem 0 3.5rem;
    }

    .app-icon {
        width: 5.5rem;
    }

    .hero-media {
        margin-top: 3rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition-duration: .01ms !important;
        animation-duration: .01ms !important;
    }

    .steam path {
        animation: none;
    }

    .btn-primary:hover,
    .btn-ghost:hover,
    .overview-return.visible:hover {
        transform: none;
    }
}
