/*
 * Front-end styles for The Victorian.
 *
 * Design tokens live in theme.json. WordPress prints them as custom
 * properties: --wp--preset--color--{slug}, --wp--preset--font-family--{slug},
 * --wp--preset--font-size--{slug}, --wp--preset--spacing--{slug}. This file
 * only references those; it defines no tokens of its own.
 *
 * The page gutter is one of them: settings.custom.gutter, printed as
 * --wp--custom--gutter. It runs in a straight line between the two frames,
 * 10px a side on the 393px phone frame and 100px on the 1602px desktop one,
 * and holds at those ends. Everything that needs a side margin (the header,
 * the content container, the footer, the carousel's bleed) reads that one
 * value, so they cannot disagree about where the page edge is.
 *
 * Measurements come from the 1602px-wide Figma frame ("Frame 13"):
 * container 1402px with 100px side margins, header 107px tall with a 1px
 * rule beneath, buttons 231x49 with a 1px border, beer cards 311x466,
 * event cards 311x550, gallery tiles 319x396. Type sizes derived from
 * measured cap heights: H1/H2 40px, card titles 36px, event titles 28px,
 * nav 20px, pre-headers 18px, body 18px on a 28px line.
 *
 * Breakpoints. A media query cannot read a custom property, so these are
 * written out, and tests/BreakpointTest.php rejects any other width:
 *   850 / 851  layout. At 850px and below this is a phone or a tablet: the
 *              hamburger, stacked hero, stacked footer. The same number
 *              moves GP's own breakpoint (inc/generatepress.php).
 *   600        phone type. Smaller headings and list text. Layout does not
 *              change here; a tablet keeps desktop type in a stacked layout.
 *   340        tiny: a phone with its text size turned up reports about
 *              320px. Drop what is decorative, keep what is needed.
 *   1024       component breakpoints, where a component's own content needs
 *              the room (the tap list's two columns, the beer list's intro).
 * Phone positions come from the 393px frames ("iPhone 16 - 1" home,
 * "iPhone 16 - 2" drinks); type faces and styles always from the desktop.
 *
 * Revised frame (2026-09-16): paper is #f6f5ee everywhere, body copy and
 * pre-headers are Nunito Sans, headings semibold, and the beer card's tap
 * line, style and town are muted.
 */

:root {
    --tv-rule: 1px solid var(--wp--preset--color--paper);
    --tv-tracking-caps: 0.02em;
    --tv-gutter: var(--wp--custom--gutter);
}

/*
 * The content container. GP centres #page at the container width and gives it
 * no side padding, and its own content padding is switched off (see
 * inc/generatepress.php), so without this the content runs to the edge of any
 * screen narrower than the container. Same shape as the header and footer:
 * as wide as the wide size, padded by the gutter, which leaves the 1402px
 * content size inside it on a desktop. Two classes, because GP's dynamic CSS
 * sets .grid-container's max-width after this file loads.
 */
.site.grid-container {
    max-width: var(--wp--style--global--wide-size);
    padding-inline: var(--tv-gutter);
}

/* Pre-header: tracked sans caps with a rule beneath, as above every section title. */
.tv-preheader {
    font-family: var(--wp--preset--font-family--body);
    font-size: var(--wp--preset--font-size--medium);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding-bottom: 5px;
    border-bottom: var(--tv-rule);
    display: inline-block;
}

/* Section headings are display caps with a two-line stack in the design. */
.tv-heading {
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--display);
    line-height: 1.5;
    text-transform: uppercase;
    letter-spacing: var(--tv-tracking-caps);
}

/*
 * Buttons are styled globally by theme.json (styles.elements.button): display
 * face, 1px paper border, transparent fill. The design's 231px minimum width
 * has no theme.json equivalent, so it lives here. Non-block links that should
 * look like buttons take the wp-element-button class.
 */
.wp-element-button,
.wp-block-button__link {
    min-width: 231px;
    text-align: center;
}

/* Bordered panel used for beer and event cards. */
.wp-block-group.is-style-panel {
    padding: var(--wp--preset--spacing--20);
    background: var(--wp--preset--color--card);
    border: var(--tv-rule);
}

/*
 * Corner cut: the bar's ticket-notch frame. Concave quarter-circle corners
 * (30px in the design) with a hairline border that follows the arc.
 *
 * The element is masked to the notched outline, so whatever it holds is
 * clipped: photos, video, a group of blocks. The border is a ring painted by
 * ::after, built from three mask layers composited top-down:
 *   outline(r)  MINUS  ( outline(r + b)  INTERSECT  box inset by b )
 * The interior stays transparent, so it sits on any background. Override
 * --r, --b and --c per instance for other radii, weights or colours.
 */
.corner-cut,
.is-style-corner-cut {
    --r: 30px;
    --b: 1px;
    --c: var(--wp--preset--color--paper);
    --R: calc(var(--r) + var(--b));
    position: relative;
    mask: radial-gradient(var(--r) at var(--r) var(--r), #0000 98%, #000)
        calc(-1 * var(--r)) calc(-1 * var(--r));
}

.corner-cut::after,
.is-style-corner-cut::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: var(--c);
    mask:
        radial-gradient(var(--r) at var(--r) var(--r), #0000 98%, #000)
            calc(-1 * var(--r)) calc(-1 * var(--r)),
        radial-gradient(var(--R) at var(--R) var(--R), #0000 98%, #000)
            calc(-1 * var(--R)) calc(-1 * var(--R)),
        linear-gradient(#000 0 0) center / calc(100% - 2 * var(--b)) calc(100% - 2 * var(--b)) no-repeat;
    mask-composite: subtract, intersect, add;
}

/* The image block puts the class on the figure; keep the img flush to it. */
.wp-block-image.is-style-corner-cut img {
    display: block;
}

/*
 * Header: menu items either side of the logo, the cluster centred, 107px tall
 * with a rule beneath.
 *
 * GP renders the logo and the nav as siblings inside .inside-header, and the
 * nav wraps its list in three more elements. Flattening those wrappers with
 * display: contents makes the list items siblings of the logo, so flex order
 * can send the first half left. Item i goes left when 2i <= N, which is
 * nth-child(i):nth-last-child(n + i + 1), so an odd extra lands on the right.
 *
 * Scoped to GP's desktop nav (#site-navigation) above the 850px layout
 * breakpoint; the phone header below takes over from there.
 */
.site-header {
    border-bottom: 1px solid var(--wp--preset--color--paper);
}

.site-header .inside-header {
    max-width: var(--wp--style--global--wide-size);
    margin-inline: auto;
    padding: 0 var(--tv-gutter);
}

.site-logo img {
    display: block;
    width: 226px;
    height: auto;
}

@media (min-width: 851px) {
    #site-navigation,
    #site-navigation .inside-navigation,
    #site-navigation .main-nav,
    #site-navigation .main-nav > ul {
        display: contents;
    }

    /*
     * The whole cluster is centred. In the design there is 26px between menu
     * words and 80px between the outer words and the logo, so links get 13px
     * of side padding and the logo 67px of margin (13 + 67 = 80).
     */
    .site-header .inside-header {
        display: flex;
        flex-wrap: nowrap;
        align-items: center;
        justify-content: center;
        min-height: 107px;
    }

    #site-navigation .main-nav > ul > li > a {
        padding-inline: 13px;
        white-space: nowrap;
    }

    /* 67px in the design; it gives way on a narrow desktop so the logo keeps its size and "Venue hire" its line. */
    .site-logo,
    .site-branding {
        order: 0;
        flex-shrink: 0;
        margin-inline: clamp(30px, 5vw, 67px);
    }

    #site-navigation .main-nav > ul > li {
        order: 1;
    }

    #site-navigation .main-nav > ul > li:nth-child(1):nth-last-child(n + 2),
    #site-navigation .main-nav > ul > li:nth-child(2):nth-last-child(n + 3),
    #site-navigation .main-nav > ul > li:nth-child(3):nth-last-child(n + 4),
    #site-navigation .main-nav > ul > li:nth-child(4):nth-last-child(n + 5) {
        order: -1;
    }
}

/*
 * Phone header, 850px and below: hamburger left, logo centred, pint glass
 * right, 84px tall over the same rule. From the 393px frames: logo 152px
 * wide, hamburger three 1px lines 27px wide and 10px apart starting 26px in,
 * glass 23.5 x 45 about 20px from the right edge. Those insets are the
 * header's own and deliberately not the page gutter, which is 10px here.
 *
 * GP prints logo, toggle wrapper, nav in that order; a three-column grid
 * places them, and the open menu takes a full row beneath. The glass is
 * printed by inc/generatepress.php at every width and only shown here.
 */
.tv-header-taps {
    display: none;
}

@media (max-width: 850px) {
    .site-header .inside-header {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        /* A fixed first row: left to auto, the closed menu's empty row takes a share of the height. */
        grid-template-rows: 84px auto;
        align-items: center;
        padding: 0 20px 0 26px;
    }

    .site-header .site-logo {
        grid-column: 2;
        grid-row: 1;
        margin: 0;
    }

    /* GP's generated logo width is .site-header .header-image; this has to outrank it. */
    .site-header .site-logo img.header-image {
        width: 152px;
    }

    .site-header #mobile-menu-control-wrapper {
        grid-column: 1;
        grid-row: 1;
        justify-self: start;
        margin: 0;
    }

    .tv-header-taps {
        display: block;
        grid-column: 3;
        grid-row: 1;
        justify-self: end;
        width: 24px;
        color: var(--wp--preset--color--paper);
        line-height: 0;
    }

    .tv-header-taps:hover {
        color: var(--wp--preset--color--muted);
    }

    /*
     * GP floats the nav right with margin-left: auto, which on a grid item
     * shrinks it to its words and parks it at the right. The open menu is a
     * full row, its links starting under the hamburger.
     */
    .site-header #site-navigation {
        grid-column: 1 / -1;
        width: 100%;
        margin: 0;
    }

    .site-header #site-navigation .main-nav > ul > li > a {
        padding-inline: 0;
    }

    .site-header #site-navigation.toggled {
        margin: 0;
        padding-bottom: 14px;
    }

    /*
     * The hamburger is drawn, not GP's icon: three hairlines to match the
     * rules on the page, which become a cross while the menu is open. GP's
     * two SVGs stay in the markup, hidden, and its script still does the
     * toggling; aria-expanded is what it sets, so that is what this reads.
     */
    .site-header #mobile-menu-control-wrapper .menu-toggle {
        padding: 12px 0;
        line-height: 0;
        background: transparent;
        color: var(--wp--preset--color--paper);
    }

    #mobile-menu-control-wrapper .menu-toggle .gp-icon {
        position: relative;
        display: block;
        width: 27px;
        height: 21px;
        background:
            linear-gradient(currentColor, currentColor) top / 100% 1px no-repeat,
            linear-gradient(currentColor, currentColor) center / 100% 1px no-repeat,
            linear-gradient(currentColor, currentColor) bottom / 100% 1px no-repeat;
    }

    #mobile-menu-control-wrapper .menu-toggle .gp-icon svg {
        display: none;
    }

    #mobile-menu-control-wrapper .menu-toggle[aria-expanded="true"] .gp-icon {
        background: none;
    }

    #mobile-menu-control-wrapper .menu-toggle[aria-expanded="true"] .gp-icon::before,
    #mobile-menu-control-wrapper .menu-toggle[aria-expanded="true"] .gp-icon::after {
        content: "";
        position: absolute;
        top: 10px;
        left: 0;
        width: 100%;
        height: 1px;
        background: currentColor;
        transform: rotate(45deg);
    }

    #mobile-menu-control-wrapper .menu-toggle[aria-expanded="true"] .gp-icon::after {
        transform: rotate(-45deg);
    }
}

/* Tiny: the glass is a shortcut to a page the menu already lists, so it is the thing to go. */
@media (max-width: 340px) {
    .tv-header-taps {
        display: none;
    }

    .site-header .inside-header {
        grid-template-columns: auto 1fr auto;
        padding: 0 16px;
    }

    .site-header .site-logo {
        justify-self: center;
    }
}

/*
 * Footer: three GP footer widget columns with hairline dividers, then the
 * copyright bar. Column contents are blocks (see patterns/footer-about.php
 * and patterns/footer-contact.php); the middle column is the Navigation Menu
 * widget on the primary menu. Rules and dividers are 1px paper, matching the
 * header. Columns stack at the 850px layout breakpoint, where the dividers go.
 */
.site-footer .footer-widgets {
    border-top: 1px solid var(--wp--preset--color--paper);
}

.site-footer .footer-widgets-container {
    max-width: var(--wp--style--global--wide-size);
    margin-inline: auto;
    padding: 60px var(--tv-gutter);
}

/*
 * GP spaces columns with a negative margin on the row and left padding on
 * each widget. Its component stylesheet loads after this one, so these need
 * the extra specificity to win. GP's margin rule carries three classes, so
 * this one carries four; with three it lost, and the whole row sat 40px left
 * of the content edge.
 */
.site-footer .footer-widgets .footer-widgets-container .inside-footer-widgets {
    margin: 0;
}

/* Columns stretch so the dividers run full height; content centres within. */
.site-footer .footer-widgets .inside-footer-widgets > div {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 0 40px;
}

.site-footer .footer-widgets .widget.inner-padding {
    padding: 0;
    margin: 0;
}

.site-footer .footer-widget-1 {
    text-align: center;
}

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

/* First column: logo, blurb and buttons, spaced as in the design. */
.tv-footer-about > * + * {
    margin-top: 40px;
}

.tv-footer-about p {
    max-width: 330px;
    margin-inline: auto;
}

/* Middle column: the menu as a plain vertical list in the display face. */
.site-footer .widget_nav_menu ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.site-footer .widget_nav_menu li {
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--medium);
    line-height: 1;
    margin-bottom: 30px;
}

.site-footer .widget_nav_menu li:last-child {
    margin-bottom: 0;
}

/* First column: the social buttons are narrower than the global minimum. */
.tv-footer-social .wp-block-button__link {
    min-width: 115px;
}

/* Third column: icon rows in the body face, a step up from body copy. */
.tv-contact {
    font-family: var(--wp--preset--font-family--body);
    font-size: var(--wp--preset--font-size--large);
}

.tv-contact-row {
    gap: 20px;
}

.tv-contact-row + .tv-contact-row {
    margin-top: 28px;
}

.tv-contact-icon {
    flex: 0 0 auto;
    margin: 0;
}

.tv-contact-icon img {
    display: block;
    height: auto;
}

@media (min-width: 851px) {
    .site-footer .footer-widgets .inside-footer-widgets > div + div {
        border-left: 1px solid var(--wp--preset--color--paper);
    }

    .site-footer .footer-widgets .inside-footer-widgets > div:first-child {
        padding-left: 0;
    }

    .site-footer .footer-widgets .inside-footer-widgets > div:last-child {
        padding-right: 0;
    }
}

/* GP's component stylesheet stacks these at a hardcoded 768px; the layout breakpoint is 850px. */
@media (max-width: 850px) {
    .site-footer .footer-widgets .footer-widgets-container .inside-footer-widgets {
        flex-direction: column;
    }

    .site-footer .footer-widgets .inside-footer-widgets > div {
        padding: 0;
    }

    .site-footer .footer-widgets .inside-footer-widgets > div:not(:last-child) {
        margin-bottom: 40px;
    }
}

/* Copyright bar: company details left, policy links right. */
.site-footer .site-info {
    border-top: 1px solid var(--wp--preset--color--paper);
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--small);
    font-weight: 700;
    text-align: left;
}

.site-footer .inside-site-info {
    max-width: var(--wp--style--global--wide-size);
    margin-inline: auto;
    padding: 40px var(--tv-gutter);
    justify-content: space-between;
    align-items: flex-start;
}

.site-footer .copyright-bar p {
    margin: 0 0 20px;
}

.site-footer .copyright-bar p:last-child {
    margin-bottom: 0;
}

.site-footer .footer-bar .widget {
    margin: 0;
}

.site-footer .footer-bar .widget_nav_menu ul {
    display: flex;
    gap: 10px;
}

.site-footer .footer-bar .widget_nav_menu li {
    margin: 0;
    font-size: inherit;
    font-weight: 700;
}

/*
 * Hero (patterns/hero.php): a Media & Text block. Photo 960x647 with a 1px
 * frame, 34px gap, then a centred text column that ends at the container
 * edge. Stacks below the block's own 600px breakpoint.
 */
.tv-hero {
    gap: 34px;
    margin-top: var(--wp--preset--spacing--30);
}

.tv-hero .wp-block-media-text__media img {
    display: block;
    width: 100%;
    aspect-ratio: 960 / 647;
    object-fit: cover;
    border: 1px solid var(--wp--preset--color--paper);
}

/* Core gives the content column 8% side padding; the design has none. */
.wp-block-media-text.tv-hero .wp-block-media-text__content {
    padding: 0;
}

/* The pre-header rule spans the column here, not just the words. */
.tv-hero .tv-preheader {
    display: block;
    margin-bottom: 30px;
}

/*
 * The design sets the heading at 40px on two lines in a 400px column, in
 * Baskerville. Libre Baskerville runs about 12% wider ("IN THE VICTORIAN"
 * measures 450px at 40px), so the hero heading drops to 34px to hold the two
 * lines. Revisit if the display face changes.
 */
.tv-hero h1 {
    font-size: 34px;
    line-height: 1.25;
    margin: 0 0 30px;
}

.tv-hero p:not(.tv-preheader) {
    margin: 0 0 30px;
}

/*
 * Venue hire (patterns/venue-hire.php, "Frame 17"): the same photo, with a
 * 405px text column at the container edge and the heading at full size,
 * since "Venue hire" fits on one line.
 */
.wp-block-media-text.tv-hero--narrow .wp-block-media-text__content {
    justify-self: end;
    width: 100%;
    max-width: 405px;
}

.tv-hero--narrow h1 {
    font-size: var(--wp--preset--font-size--display);
    margin-bottom: 17px;
}

/* A tighter stack than the home hero's 30px steps, as drawn. */
.tv-hero--narrow .tv-preheader {
    margin-bottom: 22px;
}

.tv-hero--narrow p:not(.tv-preheader) {
    margin-bottom: 18px;
}

/*
 * Stacked at 850px and below. Core only stacks Media & Text at 600px, and
 * between the two the text column is narrower than the heading's longest
 * word, which pushed the page sideways. The !important answers core's own,
 * which is there to beat the inline grid-template-columns.
 *
 * The phone frame puts the photo between the heading and the paragraph, not
 * above both. display: contents lifts the column's blocks into the hero's
 * grid so each can take its own row around the photo; their own 30px bottom
 * margins do the spacing, so the grid gap goes. The :root prefix is weight
 * only: core places the photo with three classes of its own at 600px.
 */
@media (max-width: 850px) {
    .wp-block-media-text.tv-hero {
        grid-template-columns: 100% !important;
        gap: 0;
    }

    .tv-hero > .wp-block-media-text__content {
        display: contents;
    }

    .tv-hero > .wp-block-media-text__content > * {
        grid-column: 1;
    }

    .tv-hero > .wp-block-media-text__content > .tv-preheader {
        grid-row: 1;
    }

    .tv-hero > .wp-block-media-text__content > h1 {
        grid-row: 2;
    }

    :root .wp-block-media-text.tv-hero > .wp-block-media-text__media {
        grid-column: 1;
        grid-row: 3;
        margin-bottom: 30px;
    }

    .tv-hero > .wp-block-media-text__content > p:not(.tv-preheader) {
        grid-row: 4;
    }

    .tv-hero > .wp-block-media-text__content > .wp-block-buttons {
        grid-row: 5;
    }
}

/* ------------------------------------------------------------------------
 * Page sections. Major sections sit 170px apart in the design.
 * ---------------------------------------------------------------------- */
/*
 * The carousel and the lamps run off the screen edge on purpose, by a bleed
 * worked out from 100vw. 100vw includes a classic scrollbar's width, so on
 * Windows and Linux that bleed overshoots by about 8px and the whole page
 * scrolls sideways. CSS cannot subtract the scrollbar, and layout is no job
 * for JavaScript, so the overshoot is clipped. On html, so that it applies
 * to the viewport and body never becomes a scroll container, which is what
 * breaks position: sticky when this is done with overflow: hidden on body.
 *
 * This hides accidental overflow too. Check layouts by measuring element
 * edges against the viewport, not by looking for a scrollbar.
 */
html {
    overflow-x: clip;
}

:root {
    /* Distance from the container edge to the viewport edge. */
    --tv-bleed: max(var(--tv-gutter), (100vw - var(--wp--style--global--content-size)) / 2);
}

.tv-section {
    margin-top: var(--wp--preset--spacing--60);
}

/* The last section sits 230px above the footer rule in the design. */
.entry-content > .tv-section:last-child {
    margin-bottom: calc(var(--wp--preset--spacing--60) + var(--wp--preset--spacing--40));
}

.tv-section .tv-preheader {
    margin-bottom: 30px;
}

.tv-section h2 {
    margin: 0 0 30px;
}

.tv-section .has-display-font-family {
    margin: 0 0 20px;
}

@media (max-width: 850px) {
    .tv-section {
        margin-top: var(--wp--preset--spacing--50);
    }
}

/*
 * Phone type: page and section headings are 26px on a 36px line in the phone
 * frames, against 40px on the desktop. .site-content gives the specificity
 * to beat GP's generated h1/h2 rules, which load after this file.
 */
@media (max-width: 600px) {
    .site-content :is(h1, h2),
    .site-content .tv-hero h1 {
        font-size: 26px;
        line-height: 36px;
    }
}

/*
 * Beer list (patterns/beer-list.php). Intro column 404px, then a track of
 * 311x466 cards, 21px apart, that starts 29px after the column and runs off
 * the right edge of the viewport. The arrows sit above the track, at its
 * right end, inside the container.
 *
 * Card markup, produced by the menu importer plugin (VictorianCards.php)
 * and pinned by its tests. Change it there and here together:
 *   div.tv-carousel[data-tv-carousel]
 *     div.tv-carousel__arrows > button[data-tv-carousel-prev], button[data-tv-carousel-next]
 *     ul.tv-carousel__track[data-tv-carousel-track]
 *       li.tv-beer-card (+ .tv-beer-card--dry for a tap with nothing on)
 *         .tv-beer-card__head  > span.__tap, span.__format
 *         .tv-beer-card__body  > p.__brewery, p.__name, p.__abv  (dry: p.__coming)
 *         .tv-beer-card__foot  > p.__style, p.__town
 *
 * A carousel can also be built in the editor from Groups: .tv-carousel around
 * .tv-carousel__track around the cards. inc/carousel.php adds the arrows.
 */
.tv-beer-list,
.tv-spaces {
    display: grid;
    grid-template-columns: 404px minmax(0, 1fr);
    column-gap: 29px;
    align-items: start;
}

/* The block wraps the carousel in a div; it is the grid child and must be
   allowed to shrink so the track can overflow. */
.tv-beer-list > .wp-block-kobe-menu {
    min-width: 0;
}

/* Grid children, so the flow-layout block gap must not add top margins. */
.tv-beer-list > *,
.tv-spaces > *,
.tv-tiles > *,
.tv-lamps-grid > .tv-tiles {
    margin-block-start: 0;
}

.tv-beer-list__intro {
    padding-top: 64px;
}

.tv-carousel {
    min-width: 0;
}

.tv-carousel__arrows {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-bottom: 26px;
}

.tv-carousel__arrow {
    width: 40px;
    height: 40px;
    padding: 0;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--wp--preset--color--paper);
    border-radius: 0;
    color: var(--wp--preset--color--paper);
    cursor: pointer;
}

.tv-carousel__arrow:hover {
    background: var(--wp--preset--color--paper);
    color: var(--wp--preset--color--ink);
}

.tv-carousel__arrow:disabled {
    border-color: var(--wp--preset--color--disabled);
    color: var(--wp--preset--color--disabled);
    background: transparent;
    cursor: default;
}

.tv-carousel__track {
    display: flex;
    column-gap: 21px;
    list-style: none;
    margin: 0;
    padding: 0 var(--tv-bleed) 0 0;
    margin-right: calc(-1 * var(--tv-bleed));
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    scrollbar-width: none;
}

@media (prefers-reduced-motion: reduce) {
    .tv-carousel__track {
        scroll-behavior: auto;
    }
}

.tv-carousel__track::-webkit-scrollbar {
    display: none;
}

.tv-beer-card {
    flex: 0 0 311px;
    height: 466px;
    display: flex;
    flex-direction: column;
    padding: 12px;
    margin: 0;
    background: var(--wp--preset--color--card);
    border: 1px solid var(--wp--preset--color--paper);
    scroll-snap-align: start;
}

/* :where() keeps this at element specificity, so the per-line margins below win. */
:where(.tv-beer-card) p {
    margin: 0;
}

/*
 * Card typography, measured off the design at 1:1 (cards are 311px wide in
 * both). Only the brewery and name are full paper; the head, its rule, the
 * foot rule, style and town are all muted. The name and ABV are set in px because the sizes fall between the
 * theme.json steps, and Libre Baskerville runs about 12% wider than the
 * design's Baskerville, so the name is sized to the design's *width*: that is
 * what keeps "Calmer Lies" on one line in a fixed-width card.
 */
.tv-beer-card__head {
    display: flex;
    justify-content: space-between;
    padding: 10px 0 22px;
    border-bottom: 1px solid var(--wp--preset--color--muted);
    color: var(--wp--preset--color--muted);
    font-family: var(--wp--preset--font-family--body);
    font-weight: 400;
    font-size: var(--wp--preset--font-size--medium);
    line-height: 1;
    text-transform: uppercase;
}

.tv-beer-card__tap {
    font-weight: 600;
}

.tv-beer-card__body {
    flex: 1 1 auto;
    padding-top: 60px;
}

.tv-beer-card__brewery {
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--large);
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: var(--tv-tracking-caps);
    padding-bottom: 12px;
    border-bottom: 1px solid var(--wp--preset--color--paper);
    margin-bottom: 15px;
    /* Libre Baskerville is wider than the design's Baskerville, so a long
       brewery name can wrap here where the design's did not. */
    line-height: 1.15;
}

.tv-beer-card__name {
    font-family: var(--wp--preset--font-family--display);
    font-size: 31px;
    font-weight: 700;
    line-height: 1.05;
    text-transform: uppercase;
}

.tv-beer-card__abv {
    font-family: var(--wp--preset--font-family--display);
    font-size: 24px;
    line-height: 1.2;
    margin-top: 5px;
}

.tv-beer-card__foot {
    padding-top: 13px;
    border-top: 1px solid var(--wp--preset--color--muted);
}

.tv-beer-card__style {
    color: var(--wp--preset--color--muted);
    font-family: var(--wp--preset--font-family--body);
    font-weight: 400;
    font-size: var(--wp--preset--font-size--medium);
    line-height: 1.556;
}

.tv-beer-card__town {
    color: var(--wp--preset--color--muted);
    font-family: var(--wp--preset--font-family--body);
    font-style: italic;
    font-weight: 400;
    font-size: var(--wp--preset--font-size--medium);
    line-height: 1.556;
    text-transform: uppercase;
    margin-top: 10px;
}

/* A tap with nothing on it: the head says which tap, the body says so. */
.tv-beer-card__coming {
    font-family: var(--wp--preset--font-family--display);
    font-style: italic;
    font-size: var(--wp--preset--font-size--large);
    line-height: 1.3;
    color: var(--wp--preset--color--muted);
}

@media (max-width: 1024px) {
    .tv-beer-list,
    .tv-spaces {
        grid-template-columns: 1fr;
        row-gap: 30px;
    }

    .tv-beer-list__intro,
    .tv-spaces__intro {
        padding-top: 0;
    }
}

/*
 * Page intro (patterns/drinks.php, patterns/news.php): the centred 405px
 * column that opens an inner page. Pre-header with its rule across the
 * column, h1, short blurb, 13px apart, 79px below the header rule. From
 * "Frame 15".
 *
 * The column is a limit on the pre-header and the blurb, not on the h1:
 * Libre Baskerville runs about 12% wider than the design's Baskerville, so
 * "News and events" needs about 440px at 40px where the design's fits in 405.
 */
.tv-page-intro {
    margin: 79px 0 0;
    text-align: center;
}

.tv-page-intro > * {
    max-width: 405px;
    margin: 0 auto;
}

.tv-page-intro > h1 {
    max-width: none;
}

.tv-page-intro .tv-preheader {
    display: block;
}

/* GP's dynamic CSS sets h1 to 1.2; the design's heading sits on a 60px line. */
.tv-page-intro h1 {
    margin-top: 13px;
    line-height: 1.5;
}

.tv-page-intro p:not(.tv-preheader) {
    max-width: 377px;
    margin: 13px auto 0;
}

/*
 * Tap list (patterns/drinks.php): the full board. Two bands, Keg then Cask,
 * each a 40px title over a full-width rule and two 680px columns 40px apart.
 * A row is 100px of content with 10px above and below and a rule beneath, so
 * rows pitch at 120px. One column from 1024px down; the phone sizes follow
 * the "iPhone 16 - 2" frame for position, the desktop frame for everything
 * else.
 *
 * Row markup, produced by the menu importer plugin (VictorianList.php, the
 * block's "list" view) and pinned by its tests. Change it there and here
 * together:
 *   div.tv-tap-list
 *     section.tv-tap-list__band.tv-tap-list__band--keg | --cask
 *       h2.tv-tap-list__title
 *       div.tv-tap-list__columns
 *         ul.tv-tap-list__column
 *           li.tv-tap-row (+ .tv-tap-row--dry for a tap with nothing on)
 *             span.tv-tap-row__tap
 *             div.tv-tap-row__beer
 *               p.tv-tap-row__title > span.__name, span.__abv
 *               p.tv-tap-row__maker > span.__brewery, span.__town
 *               p.tv-tap-row__style            (dry: p.__coming instead)
 *             div.tv-tap-row__flags  > abbr.__flag
 *             dl.tv-tap-row__prices  > div > dt, dd
 *
 * Type: every piece of row text is full paper; only the three uprights are
 * muted. The design's Baskerville sizes (26 / 20 / 18px) are stepped down to
 * 23 / 18 / 16px because Libre Baskerville runs about 12% wider, the same
 * correction the beer cards make. The sans sizes are the design's own.
 */
.tv-taps {
    margin-top: 22px;
    margin-bottom: calc(var(--wp--preset--spacing--60) + var(--wp--preset--spacing--40));
}

.tv-tap-list__band + .tv-tap-list__band {
    margin-top: 80px;
}

/* The cards' section titles are 700 caps; these are deliberately quiet, to offset the bold beer names. */
.tv-tap-list .tv-tap-list__title {
    margin: 0;
    padding-bottom: 8px;
    border-bottom: var(--tv-rule);
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--display);
    font-weight: 400;
    line-height: 1.5;
    letter-spacing: 0;
    text-transform: none;
}

.tv-tap-list__columns {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 40px;
}

/*
 * The column owns the four tracks and every row borrows them (subgrid), so
 * the uprights line up down the column whether a row says 5.80 or 12.00.
 * align-content keeps a short column's rows from stretching to match a
 * taller neighbour.
 */
.tv-tap-list__column {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    align-content: start;
    list-style: none;
    margin: 0;
    padding: 0;
}

/* The uprights are the cells' own left borders, so they stretch with a row that wraps. */
.tv-tap-row {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    align-items: stretch;
    min-height: 100px;
    box-sizing: content-box;
    margin: 0;
    padding: 10px 10px 9px;
    border-bottom: var(--tv-rule);
}

/* Without subgrid each row sizes its own tracks; the cells' min-widths below keep that close. */
@supports not (grid-template-columns: subgrid) {
    .tv-tap-row {
        grid-template-columns: auto minmax(0, 1fr) auto auto;
    }
}

.tv-tap-row > * {
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.tv-tap-row > * + * {
    border-left: 1px solid var(--wp--preset--color--muted);
}

/* :where() keeps this at element specificity, so the per-line rules below win. */
:where(.tv-tap-row) :is(p, dl, dt, dd) {
    margin: 0;
}

.tv-tap-row__tap {
    min-width: 26px;
    padding-right: 9px;
    font-family: var(--wp--preset--font-family--display);
    font-size: 23px;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.tv-tap-row__beer {
    padding: 0 10px 0 9px;
}

.tv-tap-row__title {
    font-family: var(--wp--preset--font-family--display);
    font-size: 23px;
    line-height: 30px;
}

.tv-tap-row__name {
    margin-right: 4px;
    font-weight: 700;
    text-transform: uppercase;
}

.tv-tap-row__maker,
.tv-tap-row__style {
    font-family: var(--wp--preset--font-family--body);
    font-size: var(--wp--preset--font-size--large);
    line-height: 28px;
}

.tv-tap-row__brewery {
    margin-right: 8px;
    font-weight: 700;
}

.tv-tap-row__town {
    font-style: italic;
}

.tv-tap-row__style {
    line-height: 22px;
}

.tv-tap-row__coming {
    font-family: var(--wp--preset--font-family--display);
    font-style: italic;
    font-size: var(--wp--preset--font-size--large);
    line-height: 1.3;
    color: var(--wp--preset--color--muted);
}

/* Held at the width of "gf" so an unflagged row keeps its uprights where the others have them. */
.tv-tap-row__flags {
    align-items: center;
    row-gap: 9px;
    min-width: 20px;
    padding: 0 10px;
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--medium);
    font-weight: 700;
    line-height: 1;
}

/* GP underlines every abbr[title] with a dotted border; the board's flags are plain. */
.tv-tap-row__flag {
    border-bottom: 0;
    text-decoration: none;
    cursor: help;
}

.tv-tap-row__prices {
    row-gap: 6px;
    min-width: 70px;
    padding-left: 10px;
    font-family: var(--wp--preset--font-family--display);
    line-height: 1;
}

.tv-tap-row__prices > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    column-gap: 14px;
}

.tv-tap-row__prices dt {
    font-size: var(--wp--preset--font-size--small);
    font-weight: 400;
}

.tv-tap-row__prices dd {
    font-size: var(--wp--preset--font-size--medium);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

@media (max-width: 1024px) {
    .tv-tap-list__columns {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 600px) {
    .tv-page-intro {
        margin-top: 40px;
    }

    .tv-page-intro .tv-preheader {
        font-size: 14px;
    }

    .tv-page-intro h1 {
        font-size: 26px;
        line-height: 36px;
    }

    .tv-tap-list__band + .tv-tap-list__band {
        margin-top: 60px;
    }

    .tv-tap-list .tv-tap-list__title {
        font-size: 30px;
        padding-bottom: 0;
    }

    .tv-tap-row {
        min-height: 78px;
        padding: 4px 4px 3px;
    }

    .tv-tap-row__tap,
    .tv-tap-row__title {
        font-size: 15px;
    }

    .tv-tap-row__tap {
        min-width: 17px;
    }

    .tv-tap-row__title {
        line-height: 20px;
    }

    .tv-tap-row__beer {
        row-gap: 5px;
    }

    .tv-tap-row__maker,
    .tv-tap-row__style {
        font-size: 13px;
        line-height: 16px;
    }

    .tv-tap-row__coming {
        font-size: var(--wp--preset--font-size--small);
    }

    .tv-tap-row__flags {
        min-width: 16px;
        padding: 0 6px;
        font-size: 15px;
    }

    .tv-tap-row__prices {
        min-width: 57px;
        padding-left: 6px;
    }

    .tv-tap-row__prices > div {
        column-gap: 8px;
    }

    .tv-tap-row__prices dt {
        font-size: 12px;
    }

    .tv-tap-row__prices dd {
        font-size: 15px;
    }
}

/*
 * Beers, bottles and books (patterns/beers-books.php). Corner-cut frame
 * 1397x616 with 150px side and 58px vertical padding inside; text column
 * 450px, 80px gap, photo 568x500 with a 1px frame.
 */
.tv-frame {
    padding: 58px 150px;
}

.tv-frame__inner {
    gap: 80px;
}

.wp-block-media-text.tv-frame__inner .wp-block-media-text__content {
    padding: 0;
}

.tv-frame__inner .wp-block-media-text__media img {
    display: block;
    width: 100%;
    aspect-ratio: 568 / 500;
    object-fit: cover;
    border: 1px solid var(--wp--preset--color--paper);
}

@media (max-width: 1024px) {
    .tv-frame {
        padding: 40px;
    }

    .tv-frame__inner {
        gap: 40px;
    }
}

@media (max-width: 600px) {
    .tv-frame {
        padding: 30px 20px;
    }
}

/*
 * Photo collage (patterns/gallery.php). Five photos placed on a 1397x1067
 * canvas in the design; positions are percentages of that box so the
 * collage scales with the container. At 850px and below it becomes a simple grid.
 */
.tv-collage__item {
    margin: 0;
}

.tv-collage__item img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

@media (min-width: 851px) {
    .tv-collage {
        position: relative;
        aspect-ratio: 1397 / 1067;
    }

    .tv-collage__item {
        position: absolute;
    }

    .tv-collage__item-1 { left: 0;      top: 0;      width: 64.8%; height: 54.1%; }
    .tv-collage__item-2 { left: 67.9%;  top: 2.8%;   width: 32.1%; height: 27.6%; }
    .tv-collage__item-3 { left: 57.3%;  top: 34.4%;  width: 42.7%; height: 35.1%; z-index: 1; }
    .tv-collage__item-4 { left: 6.3%;   top: 57.8%;  width: 42.4%; height: 35.6%; }
    .tv-collage__item-5 { left: 51.5%;  top: 73.1%;  width: 31.9%; height: 26.9%; z-index: 2; }
}

@media (max-width: 850px) {
    .tv-collage {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 12px;
    }

    .tv-collage__item {
        aspect-ratio: 4 / 3;
    }

    .tv-collage__item-1 {
        grid-column: 1 / -1;
    }
}

/*
 * Lamps and tiles (patterns/lamps-grid.php). The lamp illustrations hang at
 * the viewport edges, 237x257, above a 4x2 grid of 319x396 tiles with a
 * 40px column gap and 49px row gap.
 */
.tv-lamps {
    display: flex;
    justify-content: space-between;
    margin: 0 calc(-1 * var(--tv-bleed)) 55px;
    padding: 0 11px;
}

.tv-lamps img {
    display: block;
    width: 237px;
    height: auto;
}

.tv-tiles {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 49px 40px;
}

.tv-tile {
    aspect-ratio: 319 / 396;
    background: var(--wp--preset--color--panel);
    border: 1px solid var(--wp--preset--color--paper);
}

@media (max-width: 1024px) {
    .tv-lamps img {
        width: 140px;
    }

    .tv-tiles {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 20px;
    }
}

/* ------------------------------------------------------------------------
 * Venue hire (patterns/venue-hire.php, "Frame 17").
 * ---------------------------------------------------------------------- */
/*
 * Our spaces: the beer list's layout (see above), intro then rooms, 19px
 * apart. The rooms are a plain grid, not a carousel: there are three.
 *
 * Beside the intro: three across once each card gets 220px (from about a
 * 1300px screen; 306px at the full desktop, where the design's 347px cards
 * ran off the edge in a slider), two across below that. The 220px is chosen
 * so it is never one: two still fit at 1025px with a 17px classic
 * scrollbar taking its share of the width. The max() caps it at
 * three, so a wide screen never stretches them thin. From the 1024px
 * component breakpoint the intro moves above and the rooms go two across,
 * then one per row on a phone.
 *
 * It sits 100px under the hero rather than a full section gap, and the intro
 * starts 53px lower than the cards, which keeps the intro where the design
 * has it, about 150px below the photo.
 */
.tv-spaces {
    column-gap: 19px;
}

.tv-spaces__intro {
    padding-top: 53px;
}

.tv-spaces__intro .tv-preheader {
    display: block;
}

.tv-hero + .tv-spaces {
    margin-top: var(--wp--preset--spacing--50);
}

.tv-rooms {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(max(220px, (100% - 60px) / 3), 1fr));
    gap: 50px 30px;
}

/*
 * Editor-built Groups put a block gap above every child after the first; the
 * grid and the carousel track space their children themselves.
 */
.tv-carousel__track > *,
.tv-rooms > *,
.tv-room-card > * {
    margin-block: 0;
}

.tv-room-card__photo img {
    display: block;
    width: 100%;
    aspect-ratio: 347 / 264;
    object-fit: cover;
    border: var(--tv-rule);
}

/*
 * Baskerville at 26px in the design; Libre is wider, so 23px as on the tap list.
 * The face and weight are named because GeneratePress's h3 rule sets 400.
 */
.tv-room-card h3 {
    margin-top: 18px;
    font-family: var(--wp--preset--font-family--display);
    font-size: 23px;
    font-weight: 700;
    line-height: 1.3;
}

.tv-room-card .tv-room-card__capacity {
    margin-top: 8px;
    font-size: var(--wp--preset--font-size--small);
    line-height: 1.5;
    text-transform: uppercase;
}

.tv-room-card p:not(.tv-room-card__capacity) {
    margin-top: 18px;
    font-size: var(--wp--preset--font-size--small);
    line-height: 28px;
}

@media (max-width: 1024px) {
    .tv-rooms {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 600px) {
    .tv-rooms {
        grid-template-columns: minmax(0, 1fr);
    }
}

/*
 * Enquiries: the form column and a 751x484 framed photo, 46px apart. The
 * design starts the form 14px left of the container edge; it starts on the
 * edge here, like every other section.
 */
.tv-enquiry {
    display: grid;
    grid-template-columns: minmax(0, 616fr) minmax(0, 751fr);
    column-gap: 46px;
    align-items: start;
}

.tv-enquiry > * {
    margin-block-start: 0;
}

.tv-enquiry__form {
    padding-top: 16px;
}

.tv-enquiry .tv-preheader {
    display: block;
}

.tv-enquiry__photo {
    margin: 0;
}

.tv-enquiry__photo img {
    display: block;
    width: 100%;
    aspect-ratio: 751 / 484;
    object-fit: cover;
    border: var(--tv-rule);
}

/*
 * The enquiry form: the Bedford Coding Mailing plugin's block, whose markup
 * puts each label after its input. Boxes 58px tall (the message 180px),
 * black on the page, 31px apart. The design writes the field names inside
 * the empty boxes like placeholders; here they are real labels sitting in
 * the same place, which move up small once there is something in the box,
 * so the name never disappears while someone types. The inputs carry a
 * one-space placeholder only so :placeholder-shown can tell empty from not.
 */
.tv-enquiry .wp-block-bc-mailing-form {
    margin-top: 45px;
}

.bc-mailing-form__field {
    margin: 0 0 31px;
}

.bc-mailing-form__field input,
.bc-mailing-form__field textarea {
    display: block;
    height: 58px;
    margin: 0;
    padding: 22px 14px 6px;
    font-family: var(--wp--preset--font-family--body);
    font-size: var(--wp--preset--font-size--medium);
    line-height: 28px;
    color: var(--wp--preset--color--paper);
    background: var(--wp--preset--color--card);
    border: var(--tv-rule);
    border-radius: 0;
}

.bc-mailing-form__field textarea {
    height: 180px;
    padding-top: 30px;
    resize: vertical;
}

.bc-mailing-form__field label {
    position: absolute;
    top: 14px;
    left: 15px;
    right: 15px;
    font-size: var(--wp--preset--font-size--medium);
    line-height: 28px;
    pointer-events: none;
    transition: top 0.15s, font-size 0.15s, line-height 0.15s;
}

.bc-mailing-form__field :focus + label,
.bc-mailing-form__field :not(:placeholder-shown) + label {
    top: 4px;
    font-size: 13px;
    line-height: 18px;
    color: var(--wp--preset--color--muted);
}

@media (prefers-reduced-motion: reduce) {
    .bc-mailing-form__field label {
        transition: none;
    }
}

.bc-mailing-form__field :focus-visible {
    outline: 1px solid var(--wp--preset--color--paper);
    outline-offset: 3px;
}

.bc-mailing-form__field [aria-invalid="true"] {
    border-width: 2px;
}

/* Browsers paint autofilled boxes in their own light colours; keep them black. */
.bc-mailing-form__field input:autofill {
    -webkit-text-fill-color: var(--wp--preset--color--paper);
    box-shadow: 0 0 0 100px var(--wp--preset--color--card) inset;
}

.bc-mailing-form__error {
    margin: 8px 0 0;
    font-size: var(--wp--preset--font-size--small);
    font-style: italic;
}

.bc-mailing-form__submit {
    margin-top: -3px;
}

.bc-mailing-form__status {
    margin: 20px 0 0;
}

.bc-mailing-form.is-sent .bc-mailing-form__status {
    margin: 0;
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--large);
    line-height: 1.5;
}

@media (max-width: 850px) {
    .tv-enquiry {
        grid-template-columns: minmax(0, 1fr);
        row-gap: var(--wp--preset--spacing--30);
    }

    .tv-enquiry__form {
        padding-top: 0;
    }
}

/* ------------------------------------------------------------------------
 * Contact (patterns/contact.php, "Frame 16").
 * ---------------------------------------------------------------------- */
/*
 * Visit: a 961x646 framed map and a 405px information column, 34px apart,
 * the column centred on the map's height. It starts where the hero does on
 * the other pages. The column keeps at least 320px, so on narrow desktops
 * the map gives way and the opening hours stay on one line each.
 */
.tv-visit {
    display: grid;
    grid-template-columns: minmax(0, 961fr) minmax(320px, 405fr);
    column-gap: 34px;
    align-items: center;
    margin-top: var(--wp--preset--spacing--30);
}

.tv-visit > * {
    margin-block: 0;
}

.tv-visit__map {
    margin: 0;
}

.tv-visit__map img {
    display: block;
    width: 100%;
    aspect-ratio: 961 / 646;
    object-fit: cover;
    border: var(--tv-rule);
}

.tv-visit__info {
    text-align: center;
}

.tv-visit__info .tv-preheader {
    display: block;
    margin: 0;
}

/* The OpenStreetMap credit (inc/map-credit.php): small print, centred under the map. */
.tv-visit__credit {
    margin-top: 8px;
    font-size: 13px;
    line-height: 18px;
    color: var(--wp--preset--color--muted);
}

.tv-visit__credit a {
    color: inherit;
}

/* Each block below a 1px rule, 34px apart, as the design's "Frame 44" groups. */
.tv-visit__block {
    margin-top: 34px;
}

.tv-visit__block + .tv-visit__block {
    padding-top: 34px;
    border-top: var(--tv-rule);
}

.tv-visit__block > * {
    margin-block: 0;
}

/* Baskerville 26px caps; Libre's 700 stands in for the design's 600. */
.tv-visit__info h2 {
    margin-bottom: 13px;
    font-size: 26px;
    line-height: 36px;
    text-transform: uppercase;
}

.tv-visit__block p + p {
    margin-top: 20px;
}

.tv-visit__name {
    text-transform: uppercase;
}

.tv-visit__block strong {
    margin-right: 8px;
    font-weight: 700;
}

/*
 * We are hiring: 617px wide, 58px under the map in the design. The section
 * carries bc-mailing-section, so it is not on the page at all while the
 * hiring form is closed.
 */
.tv-visit + .tv-hiring {
    margin-top: var(--wp--preset--spacing--40);
}

.tv-hiring {
    max-width: 617px;
}

.tv-hiring .tv-preheader {
    display: block;
}

.tv-hiring .wp-block-bc-mailing-form {
    margin-top: 45px;
}

/*
 * A tickbox field: a 24px box in the same frame as the text boxes, its label
 * beside it at body size. The text fields' floating-label rules are undone
 * here, which takes the extra class to outrank them.
 */
.bc-mailing-form__field.bc-mailing-form__field--checkbox {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 14px;
}

.bc-mailing-form__field--checkbox.bc-mailing-form__field input[type="checkbox"] {
    flex: 0 0 24px;
    width: 24px;
    height: 24px;
    padding: 0;
    appearance: none;
    cursor: pointer;
}

.bc-mailing-form__field--checkbox.bc-mailing-form__field input[type="checkbox"]:checked {
    background: var(--wp--preset--color--card) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5' fill='none' stroke='%23f6f5ee' stroke-width='2'/%3E%3C/svg%3E") center / 20px no-repeat;
}

.bc-mailing-form__field--checkbox.bc-mailing-form__field input + label {
    position: static;
    flex: 1;
    font-size: var(--wp--preset--font-size--medium);
    line-height: 28px;
    color: inherit;
    pointer-events: auto;
    cursor: pointer;
}

.bc-mailing-form__field--checkbox .bc-mailing-form__error {
    flex-basis: 100%;
}

@media (max-width: 850px) {
    .tv-visit {
        grid-template-columns: minmax(0, 1fr);
        row-gap: var(--wp--preset--spacing--30);
    }

    .tv-hiring {
        max-width: none;
    }
}

/* ------------------------------------------------------------------------
 * Posts (inc/events.php): the "Published" line and the event box, here and
 * on the news listing. The single post's layout is further down.
 * ---------------------------------------------------------------------- */
/* "Published 15 September 2026": small, but plainly a sentence, not a code. */
.tv-published {
    font-size: var(--wp--preset--font-size--small);
    line-height: 1.5;
}

/* Key information for a single event, between the title and the post. */
.tv-key-info {
    margin: 30px 0 40px;
    padding: 24px 28px;
    border: var(--tv-rule);
}

.tv-key-info dl {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 12px 28px;
    margin: 0;
}

.tv-key-info__row {
    display: contents;
}

.tv-key-info dt {
    font-size: var(--wp--preset--font-size--small);
    line-height: 28px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.tv-key-info dd {
    margin: 0;
    font-size: var(--wp--preset--font-size--medium);
    line-height: 28px;
}

.tv-key-info__status {
    margin: 0 0 18px;
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--large);
    font-weight: 700;
    text-transform: uppercase;
}

@media (max-width: 600px) {
    .tv-key-info {
        padding: 18px;
    }

    .tv-key-info dl {
        grid-template-columns: minmax(0, 1fr);
        row-gap: 0;
    }

    .tv-key-info__row + .tv-key-info__row dt {
        margin-top: 12px;
    }
}

/* ------------------------------------------------------------------------
 * News and events (inc/news.php, patterns/news.php, "Frame 18" and the
 * "iPhone 16 - 3" phone frame). Under the drinks page's intro: the sort, the
 * featured post in a 1px frame, then a grid of cards, four across at 320px
 * with 40px between, posters 4:5. Everything is paper on ink; the cards sit
 * on the card black.
 *
 * Markup, from inc/news.php:
 *   div.tv-news
 *     nav.tv-news__sort > a.tv-news__sort-link[aria-current]
 *     article.tv-news-featured (--text without a poster)
 *       figure.tv-news-featured__poster > img
 *       div.tv-news-featured__body > p.tv-news__categories, h2.__title > a,
 *         p.__date, aside.tv-key-info (an event), div.__content, a.__more,
 *         div.__excerpt > p, a.__more--excerpt (phones only)
 *     div.tv-news__grid > article.tv-news-card (--text without a poster)
 *       figure.tv-news-card__poster > img
 *       div.tv-news-card__body > p.tv-news__categories, h3.__title > a, p.__date > svg.__arrow
 *     nav.tv-news__pages
 *
 * Not in the desktop frame: the sort, which only the phone frame draws; it
 * is here at every width because the order it sets applies at every width.
 * Measured within about 5px of both frames.
 * ---------------------------------------------------------------------- */
.tv-news {
    margin: 40px 0 calc(var(--wp--preset--spacing--60) + var(--wp--preset--spacing--40));
}

.tv-news > * {
    margin-block: 0;
}

/* 100px from the intro to the frame, as drawn; the sort takes the first 40. */
.tv-news > .tv-news-featured:first-child {
    margin-top: 60px;
}

.tv-news__sort + * {
    margin-top: 60px;
}

.tv-news > * + .tv-news__grid,
.tv-news__grid + .tv-news__pages {
    margin-top: 40px;
}

.tv-news__sort {
    display: flex;
    justify-content: center;
    gap: 20px;
}

.tv-news__sort-link {
    padding: 8px 12px;
    border: 1px solid transparent;
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--medium);
    line-height: 22px;
    text-decoration: none;
}

.tv-news__sort-link[aria-current] {
    border-color: var(--wp--preset--color--paper);
}

.tv-news__categories {
    font-size: var(--wp--preset--font-size--medium);
    line-height: 28px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

/*
 * Titles are set as written, not in the headings' tracked caps. The face is
 * named because GeneratePress's h3 typography would otherwise win.
 */
.tv-news-featured__title,
.tv-news-card__title {
    font-family: var(--wp--preset--font-family--display);
    font-weight: 700;
    letter-spacing: 0;
    text-transform: none;
}

.tv-news-featured__title a,
.tv-news-card__title a {
    color: inherit;
    text-decoration: none;
}

.tv-news-featured__title a:hover,
.tv-news-card__title a:hover {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
}

.tv-news-featured__poster,
.tv-news-card__poster {
    margin: 0;
}

/* Cropped from the top, never letterboxed: the top of a poster is its headline. */
.tv-news-featured__poster img,
.tv-news-card__poster img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 5;
    object-fit: cover;
    object-position: top;
}

/*
 * The featured post: 10px inside the frame, a 665px poster, and a hairline
 * 20px either side of it down to the body. The poster sets the height: the
 * body is size-contained, so it adds nothing to the row and stretches to the
 * poster's foot, and whatever does not fit is cut off (Matt, 9 October 2026:
 * no text below the poster). news.js adds .is-clipped when something was cut,
 * which brings in the fade and "Read more". clip, not hidden: a link tabbed
 * to in the hidden part cannot scroll the body out of line.
 */
.tv-news-featured {
    display: grid;
    grid-template-columns: minmax(0, 665fr) minmax(0, 695fr);
    column-gap: 20px;
    align-items: start;
    padding: 10px;
    border: var(--tv-rule);
}

.tv-news-featured--text {
    grid-template-columns: minmax(0, 1fr);
}

.tv-news-featured__body {
    align-self: stretch;
    padding: 20px 24px 20px 20px;
    border-left: var(--tv-rule);
}

.tv-news-featured--text .tv-news-featured__body {
    border-left: 0;
}

.tv-news-featured__body > * {
    margin-block: 0;
}

.tv-news-featured__title {
    margin-top: 24px;
    font-size: var(--wp--preset--font-size--display);
    line-height: 1.25;
}

.tv-news-featured__date {
    margin-top: 14px;
    padding-bottom: 26px;
    border-bottom: var(--tv-rule);
    font-size: var(--wp--preset--font-size--medium);
    line-height: 28px;
}

.tv-news-featured__body > .tv-key-info {
    margin-top: 26px;
}

.tv-news-featured:not(.tv-news-featured--text) .tv-news-featured__body {
    contain: size;
    display: flex;
    flex-direction: column;
}

.tv-news-featured__content {
    flex: 1 1 0;
    min-height: 0;
    margin-top: 26px;
    overflow: clip;
}

/* Without a poster there is no foot to cut at; stop at about a poster's height. */
.tv-news-featured--text .tv-news-featured__content {
    max-height: 600px;
}

.tv-news-featured.is-clipped .tv-news-featured__content {
    mask-image: linear-gradient(to bottom, #000 calc(100% - 4em), transparent);
}

.tv-news-featured__more {
    display: none;
    align-self: flex-start;
    margin-top: 20px;
    padding: 8px 12px;
    border: var(--tv-rule);
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--medium);
    line-height: 22px;
    text-decoration: none;
}

.tv-news-featured.is-clipped .tv-news-featured__more {
    display: inline-block;
}

.tv-news-featured__excerpt {
    display: none;
}

.tv-news-featured__content > :first-child {
    margin-top: 0;
}

.tv-news-featured__content > :last-child {
    margin-bottom: 0;
}

/* Cards: equal heights across a row, the date line at the foot of each. */
.tv-news__grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 40px;
}

.tv-news-card {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--wp--preset--color--card);
    border: var(--tv-rule);
}

.tv-news-card__body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    padding: 17px 15px 18px;
}

.tv-news-card__body > * {
    margin-block: 0;
}

.tv-news-card__title {
    margin-top: 20px;
    font-size: var(--wp--preset--font-size--x-large);
    line-height: 36px;
}

/* The title's link covers the card, so the whole card is one link. */
.tv-news-card__title a::after {
    content: '';
    position: absolute;
    inset: 0;
}

.tv-news-card__title a:focus-visible {
    outline: none;
}

.tv-news-card:has(a:focus-visible) {
    outline: 2px solid var(--wp--preset--color--paper);
    outline-offset: 4px;
}

.tv-news-card__date {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: auto;
    padding-top: 24px;
    font-size: var(--wp--preset--font-size--small);
    line-height: 28px;
}

.tv-news-card__arrow {
    flex: 0 0 auto;
}

.tv-news__pages {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    font-family: var(--wp--preset--font-family--display);
}

.tv-news__pages .page-numbers {
    padding: 8px 12px;
    border: 1px solid transparent;
    text-decoration: none;
}

.tv-news__pages .page-numbers.current {
    border-color: var(--wp--preset--color--paper);
}

.tv-news__empty {
    text-align: center;
}

@media (max-width: 1024px) {
    .tv-news__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/*
 * Phone, from "iPhone 16 - 3": the featured post stacks with a hairline
 * between poster and text, and a card turns sideways, a 118px poster beside
 * its text. The h2 drops to 26px through the site's phone heading rule.
 */
@media (max-width: 600px) {
    .tv-news__sort + *,
    .tv-news > .tv-news-featured:first-child {
        margin-top: 50px;
    }

    .tv-news-featured {
        grid-template-columns: minmax(0, 1fr);
        padding: 14px 14px 20px;
    }

    .tv-news-featured__body {
        padding: 20px 0 0;
        border-left: 0;
    }

    /*
     * The poster is on top here and sets no height, so the post shows its
     * excerpt (inc/news.php, about eight lines) in place of the body.
     */
    .tv-news-featured:not(.tv-news-featured--text) .tv-news-featured__body {
        contain: none;
    }

    .tv-news-featured__content,
    .tv-news-featured.is-clipped .tv-news-featured__body > .tv-news-featured__more {
        display: none;
    }

    .tv-news-featured__excerpt {
        display: block;
        margin-top: 26px;
    }

    .tv-news-featured__excerpt > p {
        margin: 0;
    }

    .tv-news-featured .tv-news-featured__more--excerpt {
        display: inline-block;
    }

    .tv-news-featured__poster + .tv-news-featured__body {
        margin-top: 20px;
        border-top: var(--tv-rule);
    }

    .tv-news-featured .tv-news__categories {
        font-size: var(--wp--preset--font-size--small);
    }

    .tv-news-featured__title {
        margin-top: 14px;
    }

    .tv-news__grid {
        grid-template-columns: minmax(0, 1fr);
        gap: 30px;
    }

    .tv-news-card:not(.tv-news-card--text) {
        display: grid;
        grid-template-columns: 118px minmax(0, 1fr);
        align-items: start;
    }

    .tv-news-card__poster {
        border-right: var(--tv-rule);
    }

    .tv-news-card__body {
        align-self: stretch;
        padding: 10px 14px 8px 13px;
    }

    .tv-news-card .tv-news__categories {
        font-size: 14px;
        line-height: 20px;
    }

    .tv-news-card__title {
        margin-top: 8px;
        font-size: var(--wp--preset--font-size--large);
        line-height: 30px;
    }

    .tv-news-card__date {
        padding-top: 12px;
    }
}

/* ------------------------------------------------------------------------
 * A single post (inc/single.php, "Frame 42"). GeneratePress's markup:
 *
 *   article.post.has-post-thumbnail > div.inside-article
 *     div.featured-image > img          the poster
 *     header.entry-header > p.tv-news__categories, h1.entry-title,
 *       div.entry-meta > span.tv-published
 *     aside.tv-key-info                 a single event only
 *     div.entry-content
 *   nav.tv-post-nav > a.__back, div.__steps > a.__step (span.__label,
 *     span.__arrow), or span.__step.is-disabled where there is no post
 *
 * Desktop: the poster in a 665fr column, a hairline 20px after it, the rest
 * 24px after that, as the featured post on the listing but unframed. A post
 * without a poster runs across the full width.
 * ---------------------------------------------------------------------- */
.single-post .site-main {
    margin-top: 70px;
}

.single-post .entry-header {
    padding-bottom: 26px;
    border-bottom: var(--tv-rule);
}

.single-post .entry-header > * {
    margin-block: 0;
}

.single-post .entry-title {
    margin-top: 24px;
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--display);
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: 0;
    text-transform: none;
}

.single-post .entry-header .entry-meta {
    margin-top: 14px;
    font-size: var(--wp--preset--font-size--medium);
    line-height: 28px;
}

.single-post .entry-header .tv-published {
    font-size: inherit;
}

.single-post .inside-article > .tv-key-info {
    margin: 26px 0 0;
}

.single-post .inside-article > .entry-content {
    margin-top: 26px;
}

.single-post .entry-content > :first-child {
    margin-top: 0;
}

.single-post .entry-content > :last-child {
    margin-bottom: 0;
}

@media (min-width: 851px) {
    .single-post .has-post-thumbnail {
        container-type: inline-size;
    }

    /*
     * The poster column: Lewis's 665 of 1360, but never so wide that an A4
     * poster is taller than the screen with 40px to spare above and below
     * (Matt, 9 October 2026: an A4 poster at full width is 956px tall, more
     * than a 1080p screen or a laptop shows). So big screens get the frame's
     * layout and shorter ones a narrower poster that still fits and sticks.
     * Never under 400px: on a very short window it stops shrinking, and the
     * check on the img below lets it scroll instead.
     *
     * cqi is the article's width (the container above), so the img can work
     * out the same width for itself.
     */
    .single-post .has-post-thumbnail > .inside-article {
        --tv-poster-top: 40px;
        --tv-poster-column: max(400px, min((100cqi - 20px) * 665 / 1360, (100vh - var(--tv-poster-top) - 40px) / 1.4142));

        display: grid;
        grid-template-columns: var(--tv-poster-column) minmax(0, 1fr);
        grid-template-rows: auto auto 1fr;
        column-gap: 20px;
    }

    /* Below WordPress's toolbar, for editors who are logged in. */
    .admin-bar.single-post .has-post-thumbnail > .inside-article {
        --tv-poster-top: 72px;
    }

    /* The hairline: the whole height of the right-hand column. */
    .single-post .has-post-thumbnail > .inside-article::before {
        content: '';
        grid-column: 2;
        grid-row: 1 / -1;
        border-left: var(--tv-rule);
    }

    /* The image itself is the grid item, so it is what sticks. */
    .single-post .has-post-thumbnail .page-header-image-single {
        display: contents;
    }

    /*
     * The poster stays in view, 40px from the top, while a long post scrolls
     * past, and lets go where the post ends, so it never covers the bar.
     *
     * It only sticks when the whole poster fits on the screen, because
     * sticking would hide its foot. The column above makes sure an A4 poster
     * fits; this is the guard for a taller one, or a window too short for the
     * 400px floor. CSS cannot ask "does it fit?", so the answer goes into
     * top: the poster's height is its column's width times its height-to-
     * width ratio (--tv-poster-ratio, set on the img by inc/single.php; A4 if
     * missing). When it fits, top is 40px. When it does not, the overflow
     * times 100000 sends top so far up that it never sticks, which leaves it
     * scrolling like everything else.
     */
    .single-post .has-post-thumbnail .page-header-image-single img {
        --tv-poster-height: calc(var(--tv-poster-column) * var(--tv-poster-ratio, 1.4142));

        position: sticky;
        top: calc(var(--tv-poster-top) - 100000 * max(0px, var(--tv-poster-height) + var(--tv-poster-top) + 40px - 100vh));
        grid-column: 1;
        grid-row: 1 / -1;
        align-self: start;
        display: block;
        width: 100%;
        height: auto;
    }

    .single-post .has-post-thumbnail > .inside-article > .entry-header {
        grid-column: 2;
        grid-row: 1;
        padding: 20px 0 26px 24px;
    }

    .single-post .has-post-thumbnail > .inside-article > .tv-key-info {
        grid-column: 2;
        grid-row: 2;
        margin-left: 24px;
    }

    .single-post .has-post-thumbnail > .inside-article > .entry-content {
        grid-column: 2;
        grid-row: 3;
        margin-left: 24px;
    }
}

@media (max-width: 850px) {
    .single-post .site-main {
        margin-top: 40px;
    }

    .single-post .page-header-image-single {
        margin: 0;
    }

    .single-post .page-header-image-single img {
        display: block;
        width: 100%;
        height: auto;
    }

    .single-post .has-post-thumbnail .entry-header {
        margin-top: 20px;
        padding-top: 20px;
        border-top: var(--tv-rule);
    }
}

/*
 * The bar under the post, 18px below it, ruled above and below, and never
 * covered by the poster: the poster lets go at the end of its own article.
 */
.tv-post-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 20px 52px;
    margin-top: 18px;
    padding-block: 24px;
    border-block: var(--tv-rule);
    font-family: var(--wp--preset--font-family--display);
    font-size: var(--wp--preset--font-size--medium);
    line-height: 24px;
}

.tv-post-nav a {
    color: inherit;
    text-decoration: none;
}

.tv-post-nav__back {
    padding: 12px 16px;
    border: var(--tv-rule);
}

.tv-post-nav__back:hover,
.tv-post-nav__back:focus-visible {
    background: var(--wp--preset--color--paper);
    color: var(--wp--preset--color--ink);
}

.tv-post-nav__steps {
    display: flex;
    align-items: center;
    gap: 9px;
}

.tv-post-nav__step {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.tv-post-nav__step--newer {
    margin-right: 3px;
}

.tv-post-nav__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border: var(--tv-rule);
}

.tv-post-nav__step:hover .tv-post-nav__label,
.tv-post-nav__step:focus-visible .tv-post-nav__label {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
}

.tv-post-nav__step:hover .tv-post-nav__arrow,
.tv-post-nav__step:focus-visible .tv-post-nav__arrow {
    background: var(--wp--preset--color--paper);
    color: var(--wp--preset--color--ink);
}

.tv-post-nav__step.is-disabled {
    color: var(--wp--preset--color--disabled);
}

.tv-post-nav__step.is-disabled .tv-post-nav__arrow {
    border-color: var(--wp--preset--color--disabled);
}
